enyo.ModelController and the "id" property

edited July 2015 in Enyo 2.5
From the docs on enyo.ModelController:
A controller designed to proxy an underlying enyo.Model. Other kinds may bind to this controller as if it were an enyo.Model. Using the model reserved property, the actual model may be changed without the bindings' needing to know. It will also propagate events emitted by the underlying model.

It is important to note that "model" is a reserved property name. Also note that bindings should never bind through the controller to the model directly.
Great idea. Very useful. Setup a ModelController, swap models in and out, bindings update automatically.
Wait... How do we know the model changed? Oh let's use a binding. What property should we bind? How about the primaryKey of the model, that sounds like a good one since from the docs on enyo.Model:
public primaryKey : String
Default: 'id'
The unique attribute by which the model may be indexed. The attribute's value must be unique across all instances of the specific model kind
That "unique attribute by which the model may be indexed" part sounds like just what we need. As expected it defaults to "id". Perfect that is what the API I'm interfacing with calls it too.

Cool lets try this out. controller.get('id'); wait... what... that's not the id of the model in that controller.!?!
From the docs on enyo.ModelController:
Rules of property resolution

If the controller can call hasOwnProperty() and it returns true, it will look locally; if the property is resolved to be a computed property, the requested property will be proxied from the given model, when available.
Huh? Oh great, enyo gives everything that inherits from enyo.Object I'ts own id prperty!
Ok hold on. This thing is specifically designed to proxy an enyo.Model, which has a primaryKey which defaults to "id" but we can't get the "id" of the model from the controller. What sort of mad geniusness is this?

"bindings should never bind through the controller to the model directly" so how do you bind to the id? Hmmm?


  • So I guess I can conclude that either:
    1. Nobody knows how to solve this.
    2. Nobody else is building any large data layer driven applications, where a binding to a model's id is necessary.
    3. Duplicating the actual "id" with a property like "_id" to get around this well thought out proxy implementation is the only way. Since version is still massively full of holes and none of the fixes have yet to be back ported or (better yet) a new intermediate version released in months.
  • I can understand your frustration here. My first reaction is that the framework is using too much magic in this case to figure out what the user means when they call get(). Your specific issue can be avoided by changing BaseModelController's (private parent kind declared in ModelController.js) kind to null rather than Component. As far as I can tell, ModelController has no need for the component plumbing that Component would provide so it should be safe to do.

    I'll open a ticket to follow up both on this specific issue as well as the overall design of ModelController. Thanks for the feedback.
  • So, I've been wondering about this ever since I saw the modelController in 2.4... Why not keep things simple?

    If modelController is meant to be a proxy object, then all values passed with get and set should be proxied.

    If you do want to support setting local properties on the proxy object itself, that's what setLocal and getLocal are for.

    - Any property on any object can be proxied.
    - Designing the proxied object no longer requires knowledge about the proxy.
    - Accessing local properties becomes explicit.

    - enyo.getPath and enyo.setPath cannot resolve local properties on the proxy.

    Personally, I think the con is acceptable. The need to externally access local properties on a proxy object is almost always a code smell. In the rare cases where it isn't, it's probably important enough to access the local properties explicitly.
  • Additional thought:

    Currently, in 2.4, if I pass a modelController into a modelController, I get errors, because the modelController doesn't support registered events (and the model does).

    This is fine, for a generic proxy object, but if the goal for the modelController is to be a drop-in replacement of the model, it should probably also proxy the modelControllers' api.

    Either that, or something like this:
        name: "enyo.ProxyObject",
        import: function(object) {
            while(object instanceof enyo.ProxyObject) {
                object = object.export();
            this.setLocal("source", object);
        export: function() {
            return this.getLocal("source");
        // Generic proxying functionality
        name: "enyo.ModelController",
        kind: "enyo.ProxyObject"
        // Additional functionality as needed
Sign In or Register to comment.