web-dev-qa-db-fra.com

Quelle est la liaison à double sens?

J'ai lu beaucoup de choses que Backbone ne fait pas de reliure à double sens mais je ne comprends pas exactement ce concept.

Quelqu'un pourrait-il me donner un exemple de la manière dont la liaison bidirectionnelle fonctionne dans une base de code MVC et comment elle ne fonctionne pas avec Backbone?

157
Chris M

La liaison à double sens signifie simplement que:

  1. Lorsque les propriétés du modèle sont mises à jour, l'interface utilisateur le fait également.
  2. Lorsque les éléments de l'interface utilisateur sont mis à jour, les modifications sont propagées au modèle.

Backbone n'a pas d'implémentation "intégrée" de # 2 (bien que vous puissiez certainement le faire en utilisant des écouteurs d'événement). Autres frameworks comme Knockout connecte automatiquement les liaisons bidirectionnelles .


Dans Backbone, vous pouvez facilement atteindre le n ° 1 en liant la méthode "render" d'une vue à l'événement "change" de son modèle. Pour atteindre la deuxième étape, vous devez également ajouter un écouteur de modification à l'élément d'entrée et appeler model.set dans le gestionnaire.

Voici un violon avec une liaison bidirectionnelle configurée dans Backbone.

226
McGarnagle

Une liaison bidirectionnelle signifie que toutes les modifications liées aux données affectant le modèle sont immédiatement propagées aux vues correspondantes, et que toute modification apportée à la ou aux vues (par exemple, , par l'utilisateur) sont immédiatement reflétés dans le modèle sous-jacent. Lorsque les données de l'application changent, l'interface utilisateur fait de même, et inversement.

Il s'agit d'un concept très solide pour la création d'une application Web, car il fait de l'abstraction "Modèle" une source de données atomique sûre, à utiliser partout dans l'application. Disons que si un modèle, lié à une vue, change, alors sa partie correspondante de l'interface utilisateur (la vue) reflétera cela, peu importe ce que . Et la partie de l'interface utilisateur correspondante (la vue) peut être utilisée en toute sécurité comme moyen de collecte des entrées/données utilisateur, de manière à maintenir les données de l'application à jour.

Une bonne implémentation de liaison à double sens devrait évidemment faire en sorte que la connexion entre un modèle et une ou plusieurs vues soit aussi simple que possible, du point de vue du développeur.

Il est alors tout à fait faux de dire que Backbone ne supporte pas la liaison à double sens : sans être une fonctionnalité essentielle du cadre, cela peut être effectué tout simplement en utilisant les événements de Backbone. Cela coûte quelques lignes de code explicites pour les cas simples; et peut devenir assez dangereux pour des liaisons plus complexes. Voici un cas simple (code non testé, écrit à la volée juste pour illustrer mon propos):

Model = Backbone.Model.extend
  defaults:
    data: ''

View = Backbone.View.extend
  template: _.template("Edit the data: <input type='text' value='<%= data %>' />")

  events:
    # Listen for user inputs, and edit the model.
    'change input': @setData

  initialize: (options) ->
    # Listen for model's edition, and trigger UI update
    @listenTo @model, 'change:data', @render

  render: ->
    @$el.html @template(@model.attributes)
    @

  setData: (e) =>
    e.preventDefault()
    @model.set 'data', $(e.currentTarget).value()

model: new Model()
view = new View {el: $('.someEl'), model: model}

C'est un modèle assez typique dans une application Backbone brute. Comme on peut le constater, cela nécessite une quantité décente de code (assez standard).

AngularJS et quelques autres alternatives ( Ember , Knockout …) fournissent une liaison bidirectionnelle en tant que caractéristique du premier citoyen. Ils font abstraction de nombreux cas Edge sous certains DSL et font de leur mieux pour intégrer une liaison bidirectionnelle au sein de leur écosystème. Notre exemple ressemblerait à ceci avec AngularJS (code non testé, voir ci-dessus):

<div ng-app="app" ng-controller="MainCtrl">
  Edit the data:
  <input name="mymodel.data" ng-model="mymodel.data">
</div>
angular.module('app', [])
  .controller 'MainCtrl', ($scope) ->
    $scope.mymodel = {data: ''}

Plutôt court!

Mais, sachez que certaines intégrales extensions de liaison bidirectionnelles existent pour Backbone également (en ordre subjectif brut de complexité décroissante): Epoxy , Stickit , ModelBinder

Un aspect intéressant d’Epoxy, par exemple, est qu’il vous permet de déclarer vos liaisons (attributs DOM du modèle <-> view), soit dans le modèle (DOM), soit dans l’implémentation de la vue (JavaScript). Certaines personnes n'aiment pas vraiment ajouter des "directives" au modèle DOM/(par exemple, les attributs ng- * requis par AngularJS ou les attributs data-bind d'Ember).

En prenant Epoxy comme exemple, on peut retravailler l’application Backbone brute en quelque chose comme ceci (…):

Model = Backbone.Model.extend
  defaults:
    data: ''

View = Backbone.Epoxy.View.extend
  template: _.template("Edit the data: <input type='text' />")
  # or, using the inline form: <input type='text' data-bind='value:data' />

  bindings:
    'input': 'value:data'

  render: ->
    @$el.html @template(@model.attributes)
    @

model: new Model()
view = new View {el: $('.someEl'), model: model}

Globalement, à peu près tous les frameworks JS "classiques" prennent en charge la liaison bidirectionnelle. Certains d'entre eux, tels que Backbone, nécessitent un travail supplémentaire pour le faire fonctionner en douceur , mais ce sont les mêmes qui n'appliquent pas de méthode spécifique pour le faire, pour commencer . Donc, il s'agit vraiment de votre état d'esprit.

En outre, vous pourriez être intéressé par Flux , une architecture différente pour les applications Web favorisant la liaison unidirectionnelle par le biais d’un motif circulaire. Il est basé sur le concept de re-rendu global et rapide des composants de l'interface utilisateur lors de toute modification de données afin d'assurer la cohésion et de faciliter la raisonnement sur le flux de code/données. Dans la même tendance, vous pouvez vérifier le concept de MVI (Model-View-Intent), par exemple Cycle .

43
chikamichi

McGarnagle a une excellente réponse, et vous voudrez bien l'accepter, mais je pensais mentionner (depuis que vous l'avez demandé) comment fonctionne la liaison de données.

Il est généralement implémenté en déclenchant des événements chaque fois qu'une modification est apportée aux données, ce qui entraîne la mise à jour des écouteurs (l'interface utilisateur, par exemple).

La liaison bidirectionnelle fonctionne en effectuant cette opération deux fois, en prenant soin de ne pas vous coincer dans une boucle d'événement (la mise à jour de l'événement entraînant le déclenchement d'un autre événement).

J'allais mettre ça dans un commentaire, mais ça devenait assez long ...

25
Jeff

En réalité emberjs prend en charge la liaison bidirectionnelle, qui est l’une des fonctionnalités les plus puissantes du framework javascript MVC. Vous pouvez vérifier où il est mentionné binding dans son guide d'utilisation.

pour emberjs, créer une liaison dans les deux sens consiste à créer une nouvelle propriété avec la chaîne Binding à la fin, puis à spécifier un chemin à partir de la portée globale:

App.wife = Ember.Object.create({
  householdIncome: 80000
});

App.husband = Ember.Object.create({
  householdIncomeBinding: 'App.wife.householdIncome'
});

App.husband.get('householdIncome'); // 80000

// Someone gets raise.
App.husband.set('householdIncome', 90000);
App.wife.get('householdIncome'); // 90000

Notez que les liaisons ne sont pas mises à jour immédiatement. Ember attend que tout le code de votre application soit terminé avant de synchroniser les modifications. Vous pouvez donc modifier une propriété liée autant de fois que vous le souhaitez sans vous soucier de la surcharge de la synchronisation des liaisons lorsque des valeurs sont transitoires.

J'espère que cela aide dans la mesure de la réponse originale sélectionnée.

1
weia design

Il est à noter qu'il existe de nombreuses solutions différentes qui offrent une liaison bidirectionnelle et qui fonctionnent vraiment bien.

J'ai eu une expérience agréable avec ce classeur de modèle - https://github.com/theironcook/Backbone.ModelBinder . ce qui donne aux valeurs par défaut sensibles un grand nombre de mappages de sélecteur jquery personnalisés des attributs de modèle aux éléments d’entrée.

Il existe une liste plus étendue d’extensions/plugins de dorsale sur github

0
Daniel