Angular.js
has been popularized as two-way data binding in the frontend; the idea behind two-way data binding is to keep views and models in sync. When you make a change in an input field the view the model should be updated immediately, and if you change a property in the model the view should show the current value immediately:
Backbone does not provide a mechanism to achieve this easily; however, we can do it using the event system that Backbone models provide. Figure 3.1 shows how you can make an implementation.
Backbone.View
listens for keyup
and change
events on input controls at the DOM; when a change is triggered from the DOM, Backbone.View
can extract the new value from the input and set the Model:
class FormView extends ModelView { // ... events() { return { 'click button[type="submit"]': 'saveContact', 'keyup input': 'inputChanged', 'change input': 'inputChanged' }; } inputChanged(event) { var $target = $(event.target); var value = $target.val(); var id = $target.attr('id'); this.model.set(id, value); } // ... }
When you call the set()
method on Backbone.View
, at least two events are triggered: change
and change:<fieldname>
.We can use these events to update the necessary views:
var myModel = new Backbone.Model(); myModel.on('change:foo', event => { console.log('foo changed to', event.changed.foo); }); myModel.on('change', event => { var changedKeys = _.keys(event.changed); changedKeys.forEach(key => { console.log(key, 'changed to', event.changed[key]); }); }); myModel.set('foo', 'bar'); myModel.set('baz', 'xyz'); myModel.set({ foo: 'stuff', baz: 'zxy' });
You can see the output of the preceding snippet in the following figure:
We can use these events to update the view when necessary. Indeed, the code we already have is enough to keep the ContactForm
and ContactPreview
views in sync.
this.model.on('change', this.render, this);
ContactPreview
is listening for every change in the model and re-rendering the view when something changes. However, re-rendering the whole view each time is a heavy process; it would be better if we made the changes only when necessary.
First, you will need to identify each field with an identifier:
<script id="preview-template" type="text/template"> <h3 id="name"><%= name %></h3> <ul> <li id="phone"><%= phone %></li> <li id="email"><%= email %></li> </ul> </script>
And the change event handler will update only the contents of the identified elements:
class ContactPreview extends ModelView { constructor(options) { //... // Re-render the view if something in the model // changes this.model.on('change', this.handleChange, this); } handleChange(event) { var changedKeys = _.keys(event.changed); changedKeys.forEach(key => { let $target = this.$('#' + key); if ($target) { $target.html(event.changed[key]); } }); } }
Despite the result of the two-way data binding it should be used with caution; some people don't think that two-way data binding is a good idea and consider it as an anti-pattern.
Refer to the following URLs for more information:
3.144.255.87