Introduction
In the first part, we've gone one step closer to the component's encapsulation. We solved an outer binding problem and made inner bindings possible. In this part, we are going to solve the data field name conflict which may happen among the ViewModel
s in a hierarchy.
Name Conflict
Let's imagine we are creating 2 components, an outer and an inner. We don't want to expose the internals of a component so we want to use configs to manipulate its state. In this case, a non-unique color
config in each.
For the experiment to be clear, we won't use the fix from Part 1. We change the ViewModel
in handlers instead. Outer component's color
is bound to a text field, to a label and to the color
config of the inner component.
Ext.define('Fiddle.view.OuterContainer', {
viewModel: {
data: {
color: null
}
},
config: {
color: null
},
items: [{
xtype: 'textfield',
fieldLabel: 'Enter color',
bind: '{color}',
listeners: {
change: 'colorField_change'
}
}, {
xtype: 'displayfield',
fieldLabel: 'Color',
bind: '{color}'
}, {
xtype: 'innercontainer',
bind: {
color: '{color}'
}
}],
colorField_change: function (field, value) {
this.setColor(value);
},
updateColor: function (color) {
this.getViewModel().set('color', color);
}
});
Ext.define('Fiddle.view.InnerContainer', {
viewModel: {
data: {
color: null
}
},
config: {
color: null
},
items: [{
xtype: 'textfield',
fieldLabel: 'Color',
bind: '{color}'
}],
updateColor: function (color) {
this.getViewModel().set('color', color);
}
});
If we try doing this, we'll find that bindings doesn't work properly. The reason is that both ViewModel
s contain the color
data field. To avoid this problem, we should name them uniquely. But is this convenient? And does this guarantee uniqueness?
The Extension
For this reason, the SplitViewModel
extension was created. It gives unique internal names to the data fields of a ViewModel
. As a result, ViewModels
never interfere. To complete our example, we are going to make an explicit back-reference binding as shown:
Ext.define('Fiddle.view.OuterContainer', {
viewModel: {
name: 'outercontainer',
data: {
color: null
}
},
items: [{
xtype: 'innercontainer',
bind: {
color: '{outercontainer|color}'
}
}]
});
What has changed here?
We gave a name
to the outer ViewModel
since it's anonymous (in the same file). Either way, the name
would be taken from the alias
automatically.
We gave an explicit back-reference to the outer ViewModel
using the name
and the |
char
:'{outercontainer|color}'
.
Results
ViewModel
s are now isolated from each other. We can create independent views using both ViewController
s and ViewModel
s with no worrying about ViewModel
s' interference. With this extension, bindings become very predictable.
Limitations
If you had nested views both with ViewModel
s like in the example above, then you must add an explicit back-reference to your bindings where necessary. Even if property names are unique. All you have to do is add ViewModel
's name
or type
followed by the |
char
before the property name.
Using the Code
Find the extension at GitHub:
and import it:
Ext.application({
requires: [
'Ext.vmx.app.SplitViewModel'
]
});
Combining Extensions
I find the results impressive when both extensions are used (Part 1). Take a look at this example:
There is no single handler. Everything is done with a declaration syntax. Component's state is controlled by the configuration properties but the internals are bound via the ViewModel
. I wish Sencha would have done this by default.