Sencha Ext JS 7.7 is Here – Discover What’s New and Exciting – LEARN MORE

Data Binding in the Ext JS Modern Toolkit

October 22, 2015 108 Views
Show

Sencha Ext JS

Introduction

Ext JS 6 introduced the concept of “toolkits” to describe the (primarily) visual components of the framework. Applications built using previous releases of Ext JS would upgrade to version 6 using the “classic” toolkit, and Sencha Touch applications would use the “modern” toolkit. The major benefit to both families of applications is the common core package. This not only enables developers to build Universal Applications but it also means that a Sencha Touch application upgraded to the modern toolkit now has access to lots of new features – most importantly ViewModels and data binding.

If you have never looked at these pieces, it would be a good idea to start with our View Models and Data Binding Guide. This will give you a solid foundation on data binding concepts. In this article, we will focus on how data binding works in the Modern toolkit and some useful techniques it enables.

ViewModels

The Ext.app.ViewModel class is the centerpiece that enables data binding. A ViewModel is similar to Ext.data.Model but instead of treating data as a flat set of fields, it handles data as a hierarchy of objects and properties, and it provides a bind() method to observe changes in that hierarchy.

ViewModel Hierarchy

The ViewModel Hierarchy works much like JavaScript prototype chaining. The ViewModel of a child component will inherently have access to all information contained in its parent’s ViewModel. This then continues up the parent/child chain allowing grandchildren and great-grandchildren access to higher level component data.

In the following example, we can see that child items are able to access a parent’s ViewModel. They can also add properties into the chain and non-destructively change them. Bindings will always search upward through the chain, and once a value has been found, it will be returned.

Check out this Fiddle

The above code will result in the following output:

The Don is Vito Corleone but I also know Genco Abbandando
The new Don is Sonny Corleone
Wait he’s not dead! Long live Vito Corleone!

ViewModel Lifecycle

In the Modern toolkit, the ViewModel hierarchy is established during component construction. This is a simple but crucial concept to understand because a ViewModel’s parent is a relationship which cannot be changed afterwards. For this reason, we recommend using configs to declare instances to be created as children rather than constructing instances and adding them manually.

For example, if a user were to create a button, via Ext.create, the button would be constructed without a ViewModel parent chain. If this button is later added to a container, the chain would not be reconnected.

Binding

Data binding is a feature of Ext.Widget (the base class of Ext.Component) that observes changes in a ViewModel. The changes are then simply passed along to the component’s configs via the config’s setter method. Any time a value in the ViewModel changes, all configs bound to that value will have their setter method called with the new value.

Two-Way Binding

All bindings work through the normal setter and updater workflow that developers are familiar with using in Ext JS and Sencha Touch. In a one-way binding, the configs setter will be called anytime the ViewModel value changes. This is the same for a two-way binding except that the updater is intercepted. When a config’s value successfully goes through the updater, the bound value in the ViewModel will also be changed. This in turn causes all other bindings to update.

Declaring that a config is two-way bindable is done via the conveniently name twoWayBindable config. Normally, this config is used internally, but it can be useful when writing custom views or components that have suitable config properties. For example, Ext.field.Text declares that its value config is two-way bindable like this:

twoWayBindable: {
    value: 1
}

In the following example, we can see how two-way binding on a spinner field can easily be hooked up to a formula.

Check out this Fiddle

When the spinner value changes, it’s updater will be called and hooked by the ViewModel. This triggers the binding for bottom container calling the setter for the html config. This will all work out of the box as Ext.field.Spinner is a descendant of Ext.field.Text which is configured to publish changes to its value config and also enable two-way binding.

Disabling Two-Way Binding

To disable the two-way binding in the above example, we could replace this piece of code:

bind: '{people}'

With this piece:

bind: {
    value: {
        bindTo: '{people}',
        twoWay: false  // a bind option
    }
}

The code above illustrates several aspects of binding. In the first case, we relied on the defaultBindProperty (which is “value” for a spinner). When bind is simply a string, bind options are set to their default values. To provide custom bind options, we have to be explicit and use the “bindTo” property to decorate the binding with additional attributes.

By disabling two-way binding in this example, you will see that changing the spinner will no longer result in a change to the container html.

Publishing

Any component config that is useful to other components can be published to the ViewModel. The publishes config, similar to twoWayBindable, hooks the updater and pushes config values to the ViewModel. Unlike a binding, these published values will not have their setter called if there is a change in the ViewModel.

More importantly, instead of being told where the data resides in the ViewModel (as in a bind), published config values are stored in an object named by the reference name of the component. Many components have a default publishes config, and simply by setting the reference config on that component, those values will be accessible to the ViewModel. This can be particularly useful when using a list because it’s likely that other components will be interested in which item of a list is selected.

In the following example, we use the fact that Ext.dataview.Dataview mixes in Ext.mixin.Selectable which publishes the selection property. Because this is built into the framework, is it very easy for all Ext.dataview.List instances to allow other components access to selected items

Check out this Fiddle

Forms and Fields

In the Modern toolkit, form fields have been preconfigured to work with data binding out of the box. All components that extend Ext.field.Text will publish their values to the ViewModel and have been configured for two-way binding. Checkboxes are configured to publish their checked config and are also wired up for two-way binding. Sliders also come with two-way binding and publishing for single or multiple values.

In the following example, we look at connecting multiple form elements together. We are using a Select Field to filter the form information and a checkbox to control the class of an image. Because the Ext.field.Checkbox is configured to publish its checked property, we can just use '{checkboxReferenceName.checked}' to connect to it.

Check out this Fiddle

You will also note that in the previous example one could bind directly to the ViewModel value to get the same visual result. For example, change the line:

userCls: '{friend.checked:pick("", "friend")}',

to this:

userCls: '{person.value.friend:pick("", "friend")}',

Lists

When using an Ext.dataview.List, or any ancestors of Ext.data.DataView, data binding is available per item via the itemConfig property. Record data is available inside this config by using the record object in a bind statement.

For example, you can reference a property with the name “propertyName” by binding to '{record.propertyName}'. Each item can create its own ViewModel which then allows for formulas or bindable properties of its own.

In the following example, we are using a custom formula on each item’s ViewModel to run a calculation. We are also binding to records in the lists store which allows us to template our components inside of each list item. Finally, we are binding the stores data to the value of a select field.

Check out this Fiddle

Grids

Data binding in grids is exceptionally powerful as each cell can have access to record data. A grid is like its parent Ext.dataview.List in that setting the viewModel in the itemConfig of a grid enables record binding to all cells in a row.

For example, when using a Ext.grid.cell.Widget inside a cell, you can then bind record data into its component. Another common example of Grid binding is to wire up a connection to a cell’s innerCls. This allows for custom styling of any cell based on any combination of values from the record.

In the following example, we look at both of these use cases as we create a button component inside of a grid cell and set a conditional class with the pick formatter.

Check out this Fiddle

Conclusion

The power of ViewModels and data binding really comes into focus with the modern toolkit. Due to extensive reliance on the Config System, most config properties will respond to bind requests. Common components are available out of the box with twoWayBindable and publishes configs set up for normal use which makes it faster to get your application up and running. Data binding will fundamentally change how you build your applications and everything from text fields to large grids can leverage them. No matter how you like to write applications, we think data binding will become a common tool in your developer belt.

coming soon

Something Awesome Is

COMING SOON!