Enyo 2.3.0-rc.24 to 2.5.0 Migration Notes

To ensure a smooth transition from Enyo 2.3.0-rc.24 to Enyo 2.5.0, please review the following list of changes that will likely require modifications to your existing Enyo applications.

General

Before the change:

bindings: [
    {from: '.myProp', to: '.$.myComponent.prop'}
]

After the change:

bindings: [
    {from: 'myProp', to: '$.myComponent.prop'}
]

Before the change:

enyo.kind({
    name: 'App',
    kind: 'enyo.Application',
    components: [
        {name: 'myComponent'}
    ],
    bindings: [
        {from: '.myProp', to: '.$.myComponent.prop'}
    ]
});

// all other children in the app could see a binding like this
bindings: [
    {from: '.app.$.myComponent.prop', to: '.myProp'}
]

After the change:

enyo.kind({
    name: 'App',
    kind: 'enyo.Application',
    components: [
        {name: 'myComponent', publish: true}
    ],
    bindings: [
        {from: 'myProp', to: 'myComponent.prop'}
    ]
});

// all other children in the app could see a binding like this
bindings: [
    {from: 'app.myComponent.prop', to: 'myProp'}
]

Before the change:

// unfortunately you were able to incorrectly create a kind and then use it as your namespace,
// assigning other kinds to it and using them directly
enyo.kind({

    // now there is a constructor available for MyKind
    name: 'MyKind'
});

// then you would do something like this
enyo.kind({
    
    // you are assigning a new kind constructor to another constructor
    name: 'MyKind.MyOtherKind'
});

// in this scenario you could potentially do this
new MyKind();

// and this
new MyKind.MyOtherKind();

As a rule, if you can use the new operator, it is not a namespace. Here's an example of how to avoid this error:

// either explicitly or implicitly declare a namespace; this is an example of explicitly
// declaring a namespace
MyNamespace = {};

// now when we create new kind constructors, we add them to the true namespace
enyo.kind({
    name: 'MyNamespace.MyKind'
});

enyo.kind({
    name: 'MyNamespace.MyOtherKind'
});

// notice that using the new operator on the namespace would throw an error
new MyNamespace; // -> exception

// but you can safely do this
new MyNamespace.MyKind();
new MyNamespace.MyOtherKind();

Utility

It is important to note that all Enyo Array methods have had their parameter ordering normalized to accept the target array as the first parameter. (These methods are backward-compatible.)

enyo.ObserverSupport

Before the change:

// before, this would return the a function reference that had been bound to the context
// that was passed in
var fn = this.addObserver('prop', method, context);

// we would need to use the bound function reference to remove it
this.removeObserver('prop', fn);

After the change:

// now we do not need to store the reference to the bound method to remove it
this.observe('prop', method, context);

// we simply call it the same way
this.unobserve('prop', method, context);

Before the change:

observers: {
    observerMethod: ['triggeredBy']
}

After the change:

observers: [
    // path can be an array if it is more than one property
    {method: 'observerMethod', path: 'triggeredBy'}
]

enyo.RegisteredEventSupport

enyo.ComputedSupport

Before the change:

computed: {
    computedMethod: ['triggeredBy']
}

After the change:

computed: [
    // path can be an array if it is more than one property
    {method: 'computedMethod', path: 'triggeredBy'}
]

enyo.BindingSupport

Data Layer

The 2.5.0 release includes a reworking of the Enyo data layer to normalize APIs, improve performance, and complete the implementation of its relational support (enyo.RelationalModel). This accounts for the majority of the changes made, with some changes in the API and some in how objects work together. Also note that there has been a shift in terminology in that we refer to instances of enyo.Model as "models" as opposed to "records".

enyo.Store

Before the change:

enyo.store.findLocal(ctor, opts, filterMethod);

After the change:

enyo.store.find(ctor, filterMethod, opts);

enyo.Model

enyo.Collection

Before the change:

enyo.kind({
    name: 'MyKind',
    components: [
        {name: 'myCollection', kind: 'enyo.Collection'},
        {name: 'busyPopup', showing: false}
    ],
    bindings: [
        {from: '.$.myCollection.isFetching', to: '.$.busyPopup.showing'}
    ]
});

After the change:

enyo.kind({
    name: 'MyKind',
    components: [
        {name: 'myCollection', kind: 'enyo.Collection'},
        {name: 'busyPopup', showing: false}
    ],
    bindings: [
        {from: '$.myCollection.status', to: '$.busyPopup.showing', transform: function (value) {
            // we return true if the collection is in its busy state
            return this.$.myCollection.isBusy();
            
            // or in cases where more explicit checking is required you could do something
            // like this
            var STATES = enyo.Collection.STATES;
            
            // this is the bitwise AND operator -- read the documentation to understand this
            // in greater detail
            if (value & STATES.FETCHING) return true;
            else return false;
        }
    ]
});

enyo.Source

Before the change:

enyo.store.addSources([
    {ajaxSource: enyo.AjaxSource}
]);

new enyo.Collection({defaultSource: 'ajaxSource'});

After the change:

enyo.AjaxSource.create({name: 'ajax'});

new enyo.Collection({source: 'ajax'});

See also: Enyo 2.3.0-rc.24 to 2.5.0 Release Notes