I have a backbone.js app (www.github.com/juggy/job-board) where I want to bind my form inputs directly to my model (a la Sproutcore).
Is it possible with Backbone.js (or
Have you tried Backbone.ModelBinder? It´s a nice tool to do what you need: https://github.com/theironcook/Backbone.ModelBinder
I'm working on corset, a form library for backbone.js inspired by the django forms module, but a little less ambitious in scope. Still working out the kinks, but it'll end up on github when at least semi-stable and functional.
The aim of corset is to have easily subclassed field classes so that you can build complex inputs for more complex use cases (cascading selects, etc). This approach renders each field as a separate view, and the form view is bound to a model and uses change events, blur events or submit events to update the model (configurable, blur is default). Each view has an overrideable getData function that per default maps to the jquery .val() function.
Using sensible defaults and a modelFormFactory function, we use corset (or the subset of it that is actually done yet) for rapid development, define a model using sensible attribute names, use modelFormFactory and you have instant edit UI.
I think this is a cleaner (and maybe faster) way to create an object from an input element
changed: function(evt) {
var target = $(evt.currentTarget),
data = {};
data[target.attr('name')] = target.val();
this.model.set(data);
},
without jquery:
changed: function(evt) {
var target = evt.currentTarget,
data = {};
data[target.name] = target.value;
this.model.set(data);
},
I'm not sure how SC does it but probably they listen for events too.
window.SomeView = Backbone.View.extend({
events: {
"change input.content": "contentChanged"
},
initialize: function() {
_.bindAll(this, 'contentChanged');
this.inputContent = this.$('input.content');
},
contentChanged: function(e) {
var input = this.inputContent;
// if you use local storage save
this.model.save({content: input.val()});
// if you send request to server is prob. good idea to set the var and save at the end, in a blur event or in some sync. maintenance timer.
// this.model.set({content: input.val()});
}
});
There is an even nicer way to handle this if your model includes lots of properties in it.
SampleView = Backbone.View.extend({
el: "#formEl",
events: {
"change input": "changed",
"change select": "changed"
},
initialize: function () {
_.bindAll(this, "changed");
},
changed:function (evt) {
var changed = evt.currentTarget;
var value = $(evt.currentTarget).val();
var obj = {};
obj[changed.id] = value;
this.model.set(obj);
}
});
There is a reliance on your input elements having an id the same as the what the name of the property in your model is.
I created the following technique on my site
class FooView extends MyView
tag: "div"
modelBindings:
"change form input.address" : "address"
"change form input.name" : "name"
"change form input.email" : "email"
render: ->
$(@el).html """
<form>
<input class="address"/>
<input class="name"/>
<input class="email"/>
</form>
"""
super
@
# Instantiate the view
view = new FooView
model: new Backbone.Model
$("body").html(view.el)
I've detailed the extensions to backbone you need to make on my blog
http://xtargets.com/2011/06/11/binding-model-attributes-to-form-elements-with-backbone-js/
it uses the same declarative style as the events property for binding form elements to model attributes
and here is the actual code implementing the class for you in coffeescript
class MyView extends Backbone.View
render: ->
if @model != null
# Iterate through all bindings
for selector, field of @modelBindings
do (selector, field) =>
console.log "binding #{selector} to #{field}"
# When the model changes update the form
# elements
@model.bind "change:#{field}", (model, val)=>
console.log "model[#{field}] => #{selector}"
@$(selector).val(val)
# When the form changes update the model
[event, selector...] = selector.split(" ")
selector = selector.join(" ")
@$(selector).bind event, (ev)=>
console.log "form[#{selector}] => #{field}"
data = {}
data[field] = @$(ev.target).val()
@model.set data
# Set the initial value of the form
# elements
@$(selector).val(@model.get(field))
super
@
Appologies if you don't like coffeescript. I do. Everybody is different :)