Binding custom behaviors to our application

Let's continue with our Aurelia special features exploration. In the last section, we saw value-converters, and it's impossible to not make a relationship between this feature and the binding engine of Aurelia framework. Maybe you think that both features have much in common, well, not so much really. Let's start explaining how the binding engine works.

The view resources in Aurelia framework can be divided into four categories:

  • Value converters
  • Custom attributes
  • Custom elements
  • Binding behaviors

We will focus only on the last one. It's not because the others are less important but because it will be better for us to understand how this works first and then explore the other categories. Don't worry, value-converters are already covered, and you will have a clearer idea about the difference between both features.

The value-converter acts just as a bridge interceptor between View and ViewModel (or vice versa). The binding behavior goes beyond—it has full access to the binding instance across the complete component life-cycle. This allows us to make changes in the binding behavior, such as modifying the binding throttle time, or adding customization to how the values are updated.

Remember that Aurelia is a two-way binding framework, so you don't need to worry about the data synchronization between View and ViewModel. How is this performed? Aurelia has a predefined throttle mechanism that updates values each 200 ms, by default. Could it be updated? Yes, Aurelia left us free to manage this value according to our needs. Similar to the value-converters syntax, we need to call the binding behavior in the <template> file, where we need it:

    <input type="text" value.bind="query & throttle:850">

Did you note the & symbol? It's the first difference with the already covered value-converters. When we need to define a binding behavior, we tell this to the framework using the & wildcard. Another thing you must note is that we can send parameters to the binding behaviors. Just need to add the : symbol after the behavior declaration and send the value. Its possible to send multiple params? Yes. How? Look at the example:

<input type="text" value.bind="query & customBehavior:arg1:arg2:arg3">

Also, you are allowed to declare more than one behavior in one element:

${value | upperCase & throttle:800 & anotherBehavior:arg1:arg2}

In the same way, you can define the updating time period between View and ViewModel; you have another interesting binding behavior called debounce. We can refer to this behavior in the same category of throttle, but the difference is that instead of calculating updating time, it prevents the binding from being updated until a specified interval has passed without any changes.

Maybe you will find this feature more useful; let's explain it through a real use case.

In our FIFA World Cup application, one of the most demanded features could be a search input, more specifically, an autocomplete. You already know that autocomplete component should retrieve data according to the users' input value. The big question when you develop this feature is "when should we trigger the searchByKey() method of the autocomplete? On every keypress? When the input length is greater than 2 or 3?". Really, this is a hard question; your application performance is directly compromised.

This is a good moment to think about debounce. Instead of triggering the searchByKey() method each time the user enters a value, trigger it some time after the user enters their search key:

<input type="text" value.bind="teamCountry & debounce:1000">

Other really useful binding behavior you can use is oneTime. By default, Aurelia set the preconfigured two-way binding to each ViewModel property. The big question is "do we really need this two-way binding activated for each property in our components?". Most of the time, the answer is no. Here's where oneTime comes and becomes our performance optimization partner. Really, it has a direct impact on application performance? Yes. To enable double binding, Aurelia needs to implement multiple observers looking for any changes in your component properties. With oneTime, we just tell the app—map this property to my view and forget it:

 <span>${score & oneTime}</span>

Of course, there are many more predefined binding behaviors to explore, but if you remember, we used one binding behavior defined as customBehavior in our first example. Did you note that? Guess what, Aurelia allows you to define your own binding behavior, and now it's time to learn how.

Similar to custom value-converters, you can create custom binding behaviors. Check the following example:

export class DynamicExpressionBindingBehavior {  

  bind(binding, source, rawExpression) {
    console.log('Binding : '+rawExpression)
  }

  unbind(binding, source) {
    console.log('Unbinding ')
  }
}

Like the last examples, let's explain what the code is doing.

First, you must know that similar to the toView() and fromView() methods from value-converters, custom binding behaviors need to implement two methods: bind(binding, src, expressions...) and unbind(binding, src).

On the bind() method, we are manipulating the user input value passed as a parameter. Something you must know is that on the bind() method, the first two parameters are sent by Aurelia. The other params can be one or more custom parameters; in this case, rawExpresions.

The unbind() method just ensures that our binding behavior returns to normal when our data processing ends.

Looks simple? Yes, the example looks easy, but a real implementation will be harder to understand. Don't worry, the predefined set of binding behavior commonly provided by Aurelia framework is enough for every application's purposes.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset