Qu'est-ce qu'une liaison bidirectionnelle?

173

J'ai lu beaucoup de choses que Backbone ne fait pas de liaison bidirectionnelle mais je ne comprends pas exactement ce concept.

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

Chris M
la source

Réponses:

249

La liaison bidirectionnelle signifie simplement que:

  1. Lorsque les propriétés du modèle sont mises à jour, l'interface utilisateur l'est également.
  2. Lorsque les éléments de l'interface utilisateur sont mis à jour, les modifications sont renvoyé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énements). D'autres frameworks comme Knockout câblent automatiquement la liaison bidirectionnelle .


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 le n ° 2, vous devez également ajouter un écouteur de modification à l'élément d'entrée et appeler model.setle gestionnaire.

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

McGarnagle
la source
25
La réponse est si douloureusement évidente une fois que vous la voyez. Merci beaucoup d'avoir pris le temps de fournir une réponse claire et un exemple.
Chris M
Et avec Firebase vient ... Liaison de données à 3 voies -> Affichage, Modèle, Base de données. Je pensais juste que c'était plutôt chouette.
Levi Fuller
Concis et court. +1
Karan_powered_by_RedBull
46

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

Il s'agit d'un concept très solide pour créer 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 d'interface utilisateur correspondante (la vue) reflétera cela, quoi qu'il arrive . Et l'élément d'interface utilisateur correspondant (la vue) peut être utilisé en toute sécurité comme un moyen de collecter des entrées / données utilisateur, afin de maintenir les données d'application à jour.

Une bonne implémentation de liaison bidirectionnelle devrait évidemment rendre cette connexion entre un modèle et une ou plusieurs vues aussi simple que possible, du point de vue du développeur.

Il est alors tout à fait faux de dire que Backbone ne prend pas en charge la liaison bidirectionnelle: bien que ce ne soit pas une fonctionnalité principale du framework, 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 fixations plus complexes. Voici un cas simple (code non testé, écrit à la volée juste à titre d'illustration):

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}

Il s'agit d'un modèle assez typique dans une application Backbone brute. Comme on peut le voir, 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 fonctionnalité de premier citoyen. Ils résument de nombreux cas limites sous certains DSL et font de leur mieux pour intégrer la liaison bidirectionnelle dans leur écosystème. Notre exemple ressemblerait à quelque chose comme ça 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 extensions de liaison bidirectionnelle à part entière existent également pour Backbone (par ordre brut et subjectif de complexité décroissante): Epoxy , Stickit , ModelBinder

Une chose intéressante avec Epoxy, par exemple, est qu'il vous permet de déclarer vos liaisons (attributs de modèle <-> élément DOM de la vue) soit dans le modèle (DOM), soit dans l'implémentation de la vue (JavaScript). Certaines personnes n'aiment pas du tout ajouter des "directives" au DOM / modèle (comme les attributs ng- * requis par AngularJS, ou les attributs de liaison de données d'Ember).

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

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}

Dans l'ensemble, presque tous les frameworks JS "grand public" prennent en charge la liaison bidirectionnelle. Certains d'entre eux, tels que Backbone, nécessitent un travail supplémentaire pour le faire fonctionner correctement , mais ce sont les mêmes qui n'imposent pas une manière spécifique de le faire, pour commencer. Il s'agit donc vraiment de votre état d'esprit.

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

chikamichi
la source
3
De nombreux développeurs, en particulier les développeurs de React / Flux, ne considèrent pas la liaison bidirectionnelle comme un modèle sûr pour la création d'applications à grande échelle.
Andy
28

McGarnagle a une excellente réponse, et vous voudrez accepter la sienne, mais j'ai pensé mentionner (puisque 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 (par exemple, l'interface utilisateur).

La liaison bidirectionnelle fonctionne en faisant cela deux fois, avec un peu de soin pour vous assurer que vous ne vous retrouvez pas coincé dans une boucle d'événements (où la mise à jour de l'événement provoque le déclenchement d'un autre événement).

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

Jeff
la source
2

En fait , emberjssoutient la liaison dans les deux sens, ce qui est l' une des plus puissante fonctionnalité pour un javascript framework MVC. Vous pouvez le vérifier où il le mentionne bindingdans son guide de l'utilisateur.

pour emberjs, créer une liaison bidirectionnelle 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 se mettent pas à 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 synchronisation des liaisons lorsque les valeurs sont transitoires.

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

conception de weia
la source
1

Il convient de mentionner qu'il existe de nombreuses solutions différentes qui offrent une liaison bidirectionnelle et jouent vraiment bien.

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

Il existe une liste plus étendue d'extensions / plugins de backbone sur github

Daniel
la source