My Backbone app has several views containing forms with text inputs select fields, and checkboxes. The select fields should be populated using data from my API. A given select field may be reused in multiple different forms.
What's a commonly-used approach for populating these dropdowns? Here's a solution I've rigged together...is there a more common approach?
A reusable select field which populates itself...app/views/shared/location_selection.js:
define([
'jquery',
'backbone',
'app/views/base',
'app/collections/location'
], function($, Backbone, BaseView, LocationCollection) {
'use strict';
return BaseView.extend({
initialize: function(options) {
this.options = options || {};
this.options.id = this.options.id || 'location';
this.options.showBlank = typeof this.options.showBlank != 'undefined' ? this.options.showBlank : false;
this.collection = new LocationCollection();
},
render: function() {
this.setElement('<select id="' + this.options.id + '"></select>');
var self = this;
this.collection.fetch({
success: function() {
if (self.options.showBlank) {
self.$el.append('<option></option');
}
self.collection.each(function(model) {
self.$el.append('<option value="' + model.get('id') + '">' + model.get('name') + '</option>');
});
}
});
return this;
}
});
});
And a snippet from another view which uses that view:
render: function() {
this.$el.html(this.template(this.model.toJSON()));
var locationSelectionView = new LocationSelectionView({ showBlank: !this.model.get('id') });
this.$('.location').append(locationSelectionView.render().el);
return this;
},
And the form template:
<form role="form">
<div class="form-group">
<label for="imei">IMEI</label>
<input type="text" class="form-control" id="imei" value="{{data.imei}}" />
</div>
<div class="form-group location">
<label for="location">Location</label>
</div>
<div class="checkbox">
<label><input id="master" type="checkbox"{{#if master}} checked="checked"{{/if}} /> Master</label>
</div>
</form>
If you have separate templates for both your item view and collection view you can do it this way:
var ItemView = Backbone.View.extend({
tagName: 'option',
initialize:function(){
this.template= _.template($('#menu_item_view').html());
},
render:function(){
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
var CollectionView = Backbone.View.extend({
tagName: 'select',
initialize:function(){
this.collection = new ItemCollection();
this.collection.on('sync',this.render,this);
this.collection.fetch();
},
render:function(){
_.each(this.collection.models,function( item ){
this.$el.append(new ItemView({model:item}).render().el );
},this);
return this;
}
});
Edit: just as a note, before Backbone 1.0 when you called fetch it use to trigger 'reset' but now it triggers 'sync' unless you write fetch({reset:true}). So depending on the version of Backbone you are running, be aware of that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With