gmac / backbone.epoxy

Declarative data binding and computed models for Backbone
http://epoxyjs.org
MIT License
614 stars 89 forks source link

Allow binding on attributes not yet defined #13

Closed giggio closed 11 years ago

giggio commented 11 years ago

When I am editing an existing model, binding works perfectly, because all the model attributes are set. When I am creating a new model, it does not yet have all the attributes, and binding fails. To solve that I am having to declare undefined defaults, like so: defaults: { _id: undefined, slug: undefined, name: undefined } Then binding works. I checked the code, it seems that when the parserFunct is created: https://github.com/gmac/backbone.epoxy/blob/cae1429ea51a40bea8db9d8c3e6d71e73e136aae/backbone.epoxy.js#L1193 It is not allowing for an attribute that is not yet defined. This is really anoying, as I would not have to define those attributes otherwise. After the attribute is defined, binding should happen normally.

gmac commented 11 years ago

Yeah, this is a tricky problem – that being creating a hard link between the view and an unknown model schema. The documented approach is to call applyBindings on your view after making schema changes, or else pre-define your schema using model defaults.

I've got some long-term thoughts for a dynamic bridge feature, although I'm not convinced that it would solve more problems than it creates.

giggio commented 11 years ago

To make schema changes I would have to manually copy each value from the input field to the model. Only then I could call applyBindings. This would not make sense, as this information is already present in the bindings configuration. It makes more sense to declare the defaults and let the bindings do their work. You could, somehow, make the bindings do not depend on what is currently on the model, and add the attribute to the model if it is not already there. Right now the schema of the bindings is the schema of the models, the bindings are enforcing that, and that should not be coupled on such a dynamic language such as JS.

gmac commented 11 years ago

I'd have to respectfully disagree on the dynamic nature of JavaScript being a pass for building an application around view configuration. What JavaScript is or is not capable of is inconsequential to the fundamental discussion of software design, where Model/View separation is a key concept. Abiding the principle that a view should be a disposable layer built on top of a structured application model – then relying on the view to define model schema is putting the cart before the horse.

igustafson commented 9 years ago

For what it's worth, I solved this by adding the following changes to my base model class:

var BaseModel = Backbone.Model.extend({

    schema: [],

    initialize: function() {
        // Init model attributes from schema
        var attributesToInit = {};

        _.each(this.schema, function(attributeName) {
            if (typeof this.get(attributeName) === "undefined")
            attributesToInit[attributeName] = null;
        }, this);

        this.set(attributesToInit, { silent: true })
    }
}

Schema attributes can then be defined on model classes like so:

var Dog = BaseModel.extend({

    schema: [
        "id",
        "breed",
        "age",
        "name",
        "color"
    ]
}

There is a backbone plugin that implements backbone model schemas, and provides additional common wants like type enforcement. I haven't tested whether or not it automatically makes sure all schema fields are present in the attributes object, but if not, a similar check on initialize could presumably be implemented.