Reputation: 11
I've got a little problem here:
In my Backbone.js app I save changes in a content editable on blur. This means, that when pressing the tab key the whole view is re-rendered and I loose the focus on the next element. How can I restore this?
Upvotes: 1
Views: 3468
Reputation: 174
I found that I wanted it to go to the "next" element after rendering. Also, you can't remember an element in JQuery that gets removed from the DOM. So I record the name of the input instead of the input itself. Combining the previous answers you can do something similar to below. Remember I have some assumptions in there, like names on the inputs and that I search within the fieldset.
getNextInputForName = function(desiredName) {
var desiredElement = false;
var foundElement;
$("fieldset input").each(function(index) {
if (desiredElement) {
foundElement = $(this);
return false;
}
if ($(this).attr("name") === desiredName) {
desiredElement = true;
}
});
return foundElement;
}
var myView = Backbone.View.extend({
el: $('#formElement'),
initialize: function() {
_.bindAll(this);
}
events: {
'focus input': "updateFocus"
},
updateFocus: function(event) {
this.focusedElem = $(event.target).attr("name");
},
render: function() {
// After rendering is complete
if( this.focusedElem ) {
getNextInputForName(this.focusedElem).focus();
}
}
});
Upvotes: 0
Reputation: 542
You can maintain a property, either in the view (as a plain attribute, as in the example below) or model, to store the currently focused element. Whenever focus changes, update the property.
After re-rendering stuff, set the focus to the element manually.
Here is a minimal code:
var myView = Backbone.View.extend({
el: $('#formElement'),
initialize: function() {
_.bindAll(this);
}
events: {
'focus input': "updateFocus"
},
updateFocus: function(event) {
this.focusedElem = $(event.target);
},
render: function() {
// After rendering is complete
this.focusedElem.focus();
}
});
Upvotes: 3
Reputation: 3750
I use a dedicated ViewModel and View for every input. It has a special readValue/writeValue methods which update element instead of recreating it. It looks this way:
var TextInput = Backbone.Model.extend({ // abstract
defaults: {
value: '', // text
visible: true, // determines if input element is visible
readonly: false, // determines if input element is read only
enabled: true, // determines if input element is enabled
delay: 750 // view/model sync latency
}
});
var TextInputView = Backbone.View.extend({
template: _.template($('#text-input').html()),
initialize: function (options) {
this.model.bind('change:visible', this.render, this);
this.model.bind('change:readonly', this.render, this);
this.model.bind('change:enabled', this.render, this);
this.model.bind('change:value', this.readValue, this);
},
events: {
'change input': 'writeValue',
'keyup input': 'writeValue'
},
render: function () {
$(this.el).html(this.template(this.model))
.find('input')
.prop({
readonly: this.model.get('readonly'),
disabled: !this.model.get('enabled')
})
.toggleClass('hidden', !this.model.get('visible'));
this.readValue();
return this;
},
changeTimer: null,
writeValue: function () {
if (this.changeTimer)
clearTimeout(this.changeTimer);
var that = this;
this.changeTimer = setTimeout(function () {
that.model.set({ value: that.$('input').val() });
}, this.model.get('delay'));
},
readValue: function () {
if (this.$('input').val() != this.model.get('value'))
this.$('input').val(this.model.get('value'));
}
});
Upvotes: 1