Introduction
This tip is created for advanced users who want to squeeze a little bit more juice from MVVM in Ext JS, for those who have an intuitive knowledge that some things could be done better.
In this part, we are going to review a self binding trick. What is it? Briefly, it is a data binding within a custom component.
This is related to the encapsulation principle. When you create your own component with its configuration properties (configs), you wish them to be bound to some of the inner components. For example, a projectName
config to be displayed in a label, or a locked
flag to affect the availability of some fields.
Let's explore the ways to do this.
Background
Here is the official MVVM guide from Sencha: View Models & Binding.
In these examples, Sencha uses one ViewModel
for everything. And binds the data in a single view. This is acceptable for a small project but this definitely will be a problem in a big one. Someday, you'll come up with creating independent reusable components and using the benefits of MVVM at the same time.
Example
Take a look at this example. Here, we want to create a reusable component, a grid with users. The 'Remove' button contains the name of a selected user. The grid may be locked for changes with a configuration property. Let's call it readOnly
. In this example, we'll do it with the 'Set Read only' button outside of the component. We also want to bind to grid's selection in the outer container.
Our Goals
- Use the configuration properties to change the component's state
- Use the benefits of MVVM. No handlers, just data bindings
- Be able to use the grid in a container with its own
ViewModel
or without
Problems
If we start, we would face some limitations of the framework:
- A component cannot make a bind between its configuration properties and the inner components.
- An outer component cannot bind to the component's published properties if the inner component has a
ViewModel
(ticket #EXTJS-15503).
They look strange for me so I've decided to make a fix. It's called Ext.vmx.mixin.Bindable
and it solves these problems.
Using the Code
So with this fix, we can write a component we want. Take a look at this piece of code.
Ext.define('Fiddle.view.UsersGrid', {
extend: 'Ext.grid.Panel',
xtype: 'usersgrid',
viewModel: {
},
config: {
readOnly: false
},
publishes: ['readOnly'],
tbar: [{
text: 'Add',
itemId: 'addButton',
bind: {
disabled: '{readOnly}'
}
}, {
text: 'Remove',
itemId: 'removeButton',
bind: {
disabled: '{readOnly}',
text: 'Remove {selection.name}'
}
}],
columns: [{
dataIndex: 'id',
header: 'id'
}, {
dataIndex: 'name',
header: 'name'
}]
});
Looks pretty elegant, right? Here is what we've done:
- Defined an empty
viewModel
- Defined a
readOnly
config - Marked it as a published in the
publishes
section - Created data bindings to the
readOnly
config - Created data binding to a
selection
config. It was also marked as a published by Ext.grid.Panel
Benefits
So what's good with it? There is something I personally like:
- The component is now more independent. You can use it within a container which has a
ViewModel
or doesn't. There is no difference now. - You don't need to define anything in a
ViewModel
. This is automatically done with the publishes
section. - You are free of creating any handlers for your configuration properties. Everything is handled by the MVVM engine. So the code becomes smaller.
I've been using this extension in my projects for about 2 years and I haven't had any issues. It is backward compatible so you can use it in your projects and it won't break anything.
Don't forget to include 'Ext.vmx.mixin.Bindable'
somewhere in the requires
section of your application.
Cons
One thing we have to keep in mind using this approach. "Don't nest data objects more deeply than necessary" - a recommendation from Sencha. Other way, we may face a performance issue. For example, I'm not going to create a recursive comment tree where each comment is displayed in a component with a ViewModel
. But I had no performance slowdown with 3-4 levels ViewModel
hierarchy.
Source
All right, if you like it, please check out an online demo at Sencha Fiddle:
and the source code at GitHub:
To Be Continued
In the second part, we'll talk about an even stronger component isolation speaking in terms of Ext JS MVVM. At the moment, you may still mess around with a ViewModel
hierarchy, with data names, should they be unique, should you use references and why do they work in one direction only, etc. So in the next part, we'll talk about how to make MVVM more predictable in a growing project.
Updates