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
In
enyo.Control
, theresized()
method has been renamed asresize()
and the default event handler has been renamed fromresizeHandler()
tohandleResize()
. If you have overloaded the event handler, you will need to rename your overload method ashandleResize()
, and if you are callingresized()
you will instead need to callresize()
.The way in which bindings are initialized and resolved has been rewritten so that you no longer need to prefix the
to
andfrom
properties with a dot ("."). While the old syntax will still work, it results in unnecessary string parsing, so you should use the new syntax for a slight boost in performance.
Before the change:
bindings: [
{from: '.myProp', to: '.$.myComponent.prop'}
]
After the change:
bindings: [
{from: 'myProp', to: '$.myComponent.prop'}
]
A new API allows components that are intended to be accessible by other components to set a
publish
property totrue
; the component will then be accessible without needing to use the$
prefix. Note that this should not be used unless the component is exposed outside the scope of its instance owner.An example of an acceptable use case would be an
enyo.Application
that exposes its components to other nested components.
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'}
]
- In previous versions of Enyo, it was possible to incorrectly use a kind constructor as a namespace. This has been fixed, but if you were relying on the old behavior, you may need to make a few minor updates to your apps to make them function as before.
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
The
enyo.setPath()
method now accepts a configuration hash as its third parameter. This affects anyset()
call on anenyo.Object
or subkind ofenyo.Object
. Backward compatibility with the booleanforce
flag has been maintained, but with the options hash you can setsilent
andcreate
flags as well. Theforce
flag behaves the same as before. Settingsilent: true
will prevent change notifications from being emitted, while settingcreate: false
will prevent the path from being automatically created (overriding the default behavior).Several native JavaScript types have been polyfilled (when necessary) to allow us to reliably use ECMA-defined methods. While the Enyo exposed versions are still available, they now call the native implementations for consistency. Here is a list of Enyo methods and the native methods they now call. Note that it is now preferable, for efficiency, to use the native implementation when possible:
enyo.trim
->String.prototype.trim
enyo.keys
->Object.keys
enyo.indexOf
->Array.prototype.indexOf
|String.prototype.indexOf
enyo.lastIndexOf
->Array.prototype.lastIndexOf
|String.prototype.lastIndexOf
- (new)
enyo.findIndex
->Array.prototype.findIndex
enyo.find
->Array.prototype.find
enyo.forEach
->Array.prototype.forEach
enyo.map
->Array.prototype.map
enyo.filter
->Array.prototype.filter
- (new)
enyo.where
->Array.prototype.find
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.find()
will now returnundefined
instead offalse
, per ECMA 6 (ECMA-262) draft specification.Object.create
polyfill has been added and is now used internally.
enyo.ObserverSupport
The internal mechanics of observers have been changed, yielding some performance gains. As part of these changes,
addObserver()
and its (new) preferred alias,observe()
, return the callee for chaining instead of the method passed in. When passing in a context parameter, it no longer needs to bind the method. This means that when callingremoveObserver()
or its (new) preferred alias,unobserve()
, you pass the original parameters, including the context to be matched.addObserver
->observe
removeObserver
->unobserve
notifyObservers
->notify
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);
- There is a new preferred way of declaring observers in a kind--as an array (the previous structure is still available, but has been deprecated):
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
Added alias as
enyo.EventEmitter
Added preferred aliases for previous API as follows (either may be used):
addListener
->on
removeListener
->off
triggerEvent
->emit
enyo.ComputedSupport
The
defaultValue
property did not properly and has been completely removed.Kinds that want to use
enyo.ComputedSupport
do not need to add it as a mixin, as it will automatically be added if there is acomputed
property in the kind definition.As in
enyo.ObserverSupport
, thecomputed
property should now be declared as an array:
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
- The
refreshBindings()
andrebuildBindings()
methods are no longer relevant, and have been removed.
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
enyo.Store
has been implemented as a protected class and is not intended to be subclassed directly. Theenyo.store
singleton is an internally-used interface and runtime database. It does not have any interaction with sources (enyo.Source
).The
addSources()
,removeSource()
, andremoveSources()
methods have been removed.enyo.store
no longer tracks, stores or creates collections (enyo.Collection
). TheaddCollection()
,removeCollection()
,getCollection()
, andcreateCollection()
methods have all been removed.enyo.store
no longer has a public API for creating instances of models (enyo.Model
). ThecreateRecord()
,getRecord()
,addRecord()
,destroyRecord()
, andremoveRecord
methods have all been removed.The
find()
method is now the equivalent offindLocal()
with modified parameters;findLocal()
has been kept for name compatibility, but now callsfind()
internally. The parameters were brought in line with many of the other data layer methods, which accept an optionaloptions
hash as the last parameter. Note that the options have changed to the following:all
(boolean): iftrue
, implies that an array of multiple models will be returned; iffalse
, only a single model will be returned.context
: the context under which to execute the filter-method provided as the second parameter.
For more information, see the documentation for the method.
Before the change:
enyo.store.findLocal(ctor, opts, filterMethod);
After the change:
enyo.store.find(ctor, filterMethod, opts);
enyo.Model
enyo.Model
now has its default behavior controlled by theoptions
property. These options will be fully documented to for better understanding.The
defaultSource
property is now calledsource
; its value may be a string, an array of strings, an instance ofenyo.Source
, or an array ofenyo.Source
instances.The
readOnly
property has been removed.The
urlRoot
property is no longer used on a model.The
mergeKeys
property has been removed.Any computed properties for
enyo.Model
are now declared and used exactly the same as for all other kinds and cannot be declared in theattributes
hash. They also are not included in the return values oftoJSON()
orraw()
.The
setObject()
method has been removed, butset()
still accepts an object as well as a string path.There is no
destroyLocal()
method; there is onlydestroy()
, which will be a local action (only removing the model from the running application and store) unless specific flags are set in theoptions
hash.The
didDestroy()
method was removed; the equivalent behavior can now only be achieved by forcing a remote destroy via a source and passing asuccess
method via the options hash to thedestroy()
method.The
didFetch()
method is now calledfetched
; it has different parameters and should not need to be overloaded like before.The
didCommit()
method is now calledcommitted()
; it, too, has different parameters and should not need to be overloaded like before.The
didFail()
method is now callederrored()
; it has different parameters and should not need to be overloaded like before.The
toJSON()
method now returns a JSON-parseable object instead of a JSON-serialized string.
enyo.Collection
enyo.Collection
now has its default behavior controlled by theoptions
property. These options will be fully documented for better understanding.The filtering API was completely removed. There is a new kind,
enyo.BucketFilter
, that acts as a proxy for a given collection and can automatically maintain multiple filtered states. In a future release, there will also be anenyo.ProgressiveFilter
that will help in text filtering for a collection.With the removal of the old filtering API, the
filtered
,filters
,activeFilter
, andfilterProps
properties no longer exist. TheclearFilter()
method has been removed, as well.The
instanceAllRecords
property has been removed sinceenyo.Collection
no longer delays the instantiation of models.The
records
property, previously public, is now a private property calledmodels
.The
preserveRecords
property no longer exists; models in a collection are always preserved unless thedestroy
option istrue
in the options hash when thedestroy()
method is called.The
fetchAndReplace()
andfetchAndDestroy()
methods have been removed; the equivalent functionality can now be managed via the options passed to theadd()
method.The
didFetch()
method is now calledfetched()
; it has different parameters and should not need to be overloaded like before.The
didFail()
method is now callederrored()
; it, too, has different parameters and should not need to be overloaded like before.The
toJSON()
method now returns a JSON-parseable object instead of a JSON-serialized string.The
merge()
method has been removed, as the behavior it implemented can now controlled via options passed to theadd()
method.The
add()
method has been significantly reworked and now expects anoptions
hash as the second parameter.The
remove()
method has been significantly reworked and now accepts an optionaloptions
hash as a second parameter.The
reset()
method has been replaced byempty()
, which has multiple uses, but can be made to replicate the behavior ofreset()
via its optional parameters.The
removeAll()
method has been replaced byempty()
.The
destroyAll()
method has been replaced byempty()
, which can be made to replicate the behavior ofdestroyAll()
through its optional parameters.The
createRecord()
method has been removed.The
recordChanged()
optional method is no longer supported.The
destroy()
method has been reworked and now accepts anoptions
hash, much likeenyo.Model.destroy()
.You can now commit from a collection; a new
committed()
method has been added, which should not need to be overloaded.The
isFetching
property has been replaced by the more sophisticatedstatus
property. See the exposed constants (enyo.Collection.STATES
) for available states. We recommended that you read the documentation to fully understand the various states and how to use them to meet your needs.The
status
value will be a hexadecimal numeric value; you may use bitwise operators onstatus
for explicit state control, or make use of the new convenience methodsisBusy()
,isError(),
andisReady()
, which should be suitable for many general use cases (like the one below).
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
enyo.Source
is no longer considered to be a singleton and is not automatically available in a given application. Sources that need to be available to the app must be instanced, usually within theenyo.ready()
function call, where theenyo.Application
instance is created. It should also be noted that sources no longer interact withenyo.Store
at all.
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'});
enyo.AjaxSource
andenyo.JsonpSource
(both based onenyo.XHRSource
) no longer inspect a collection or model for aparams
property. Instead, use theoptions
hash passed tofetch()
,commit()
, ordestroy()
(when using a source) to pass theparams
property for the desired behavior.
See also: Enyo 2.3.0-rc.24 to 2.5.0 Release Notes