Reputation: 131
I'm having two form elements, both 2-way-databinded via backbone.stickit. The second form element (#input) is just cosmetics - there for showing it's actually working.
The idea is that my View gets (re)rendered,every time the option inside the dropdown (#select) menu gets changed.
I'm trying to achieve that by catching the the 'changed' event of #select and call this.render() to (re)render the view.
Apparently that doesn't work. The selected option doesn't get saved back into the model and I fail to understand why.
I'm not looking for a solution, rather than an explanation, why the following code doesn't work. The solution (as in: works for me) is part of the fiddle - commented out.
HTML:
<script type="text/template" id="tpl">
<h1>Hello <%= select %></h1>
<select id="select">
</select>
<p>Select:
<%= select %>
</p>
<hr>
<input type="text" id="input">
<p>Input:
<%= input %>
</p>
</script>
<div id="ctr"></div>
JavaScript:
Foo = Backbone.Model.extend({
defaults: {
select: "",
input: "",
}
});
FooView = Backbone.View.extend({
el: '#ctr',
template: _.template($('#tpl').html()),
initialize() {
this.model.bind('change', function() {
console.log("model change:");
console.log(this.model.get('select'));
console.log(this.model.get('input'));
}, this);
//this.model.bind('change:select', function() { this.render(); }, this); // <--------------------- WORKS
},
render: function() {
this.$el.html(this.template(this.model.toJSON()));
this.stickit();
return this;
},
events: {
'change #select': function(ev) {
console.log('change event triggered:');
console.log(this.model.get('select'));
console.log(this.model.get('input'));
this.render(); // <--------------------- DOES NOT WORK - WHY?
},
/* 'click #render': function(ev) {
console.log('render event triggered:');
console.log(this.model.get('select'));
console.log(this.model.get('input'));
this.render();
} */
},
bindings: {
'#input': 'input',
'#select': {
observe: 'select',
selectOptions: {
collection: function() {
return [{
value: '1',
label: 'Foo'
}, {
value: '2',
label: 'Bar'
}, {
value: '3',
label: 'Blub'
}]
}
}
},
},
});
new FooView({
model: new Foo()
}).render();
https://jsfiddle.net/r7vL9u07/9/
Upvotes: 1
Views: 1233
Reputation: 8993
The reason it does not work to call this.render()
from within your change #select
event handler is because you are disrupting the two-way data binding that Backbone.stickit is providing you. The flow goes something like the following:
change #select
handler fires and calls this.render()
.render
repopulates #ctr
with a new select menu with no selected option
.#select
.#select
, but since it contains no selected option
the value is undefined
.model
's select
attribute to undefined
.The reason it works if you move the this.render()
call to within the model
's change:select
handler is because Backbone.stickit is able to correctly update the model without the DOM changing before it gets the chance.
Upvotes: 1