The problem – Data is not exposed as we need

One of the common problems we could have is the date formatting. In other code languages such as Java, you have a utility class like SimpleDateFormat, which converts the Date() object to a more friendly human reading format. In JavaScript, we have some libraries to do that job, but they are not so simple to call. Let's see an example.

You get the current date in your ViewModel component; then, you pass that value to the View layer:

export class Example {
      constructor() {
        this.changeDate();
        setInterval(() => this.changeDate(), 3000); //<<-- This method will be executed each 3 seconds
      }

      changeDate() {
        this.currentDate = new Date(); //<<-- Get the current date
      }
}

In our View file, we map the currentDate value to be displayed:

<template>
      ${currentDate}
</template>

When you run the example, you will be displayed in your screen the following output:

Sun Feb 25 2018 14:06:37 GMT-0300 (-03) 

Okay, we can do better; it's time to call our value-converters, but exactly, what is a value converter? The Aurelia documents explain it really good:

"A value converter is a class whose responsibility is to convert view-model values into values that are appropriate to display in the view and vice versa."

That being said, let's create one value-converter file just for example purposes. Since we are working with a Date() value, we will work with the moment plugin.

If you don't have it in your dependencies tree, just import it from npm repositories:

npm install moment --save 

Then, first of all, import this library in our value-converter file:

import moment from 'moment';

export class DateFormatValueConverter {
     toView(value) {
       return moment(value).format('M/D/YYYY h:mm:ss a');
     }
}

Okay, now let's explain how this works:

  • You know that Aurelia is a convention over configuration-based framework. With that being said, if you name this class terminating it ValueConverter, the framework will use this class as a custom value converter without any more configuration.
  • The toView() method is inherited from the Aurelia ValueConverter interface. It defines the data flow direction, if it comes to ViewModel to View, or vice versa, you have the fromView() method.
  • Those value-converter methods could receive more than one parameter.

Now, we just need to import this value-converter in our View file like any other dependency, using the <require> tag:

<template>
      <require from="./date-format"></require> <<-- Path to your value converter

Now, we need to add the converter to our binding syntax:

<template>
      <require from="./date-format"></require>
      ${currentDate | dateFormat} <br/> <<-- Name mapped for our value converter
</template>

Now, refresh your browser window:

2/25/2018 2:25:36 pm

So much better, right? Well, this same dynamic can be applied to number format converters, currency, and so on. Let's make the example a little more advanced—what if we need to show multiple date formats across our entire application? Should we define a value-converter file per format we need? It's a valid option, but not the most effective. Do you remember when we said that value-converter interface methods can receive more than one parameter? Well, what if we send the date format as parameter too? Let's try to see what happens:

toView(value, format) {
        return moment(value).format(format);
}
You can specify a default format in case no one was provided: toView(value, format = 'M/D/YYYY'){ ... }

Nice, our formatter now accepts the format pattern as a parameter. It's not the magic of Aurelia; it's because we are using moment.js a nice JavaScript library, which allows us to perform this kind of operations.

Now, in our View file, we can add as many time formats as we need:


${currentDate | dateFormat:'h:mm:ss a'} <br/>
${currentDate | dateFormat:'M/D/YYYY h:mm:ss a'} <br/> ${currentDate | dateFormat:'MMMM Mo YYYY'} <br/>

Now, look at your browser window:

2:33:11 pm 
2/25/2018 2:33:11 pm
February 2nd 2018

That was very nice. Now it's time to take a look at a little more complicated example but with a more common usage—arrays order.

You know how to retrieve data from one backend service; often this data is retrieved as an array object and shown as a list in the View file. That's all okay, but what if we need to order these values according to some property? Look at the code example:

export class ArraySortingValueConverter {
      toView(array, config) {
        let sorter = (config.direction || 'ascending') === 'ascending' ? 1 : -1;
        return array.sort((a, b) => {
          return (a[config.propertyName] - b[config.propertyName]) * sorter;
        });
      }
}

What are we doing? Let's explain.

We are receiving two parameters, one array, and one config property. The config property is an object with two values: config.direction, which can be one of these two options: ascending or any other string. Depending on that, the sorter can order the list incrementing values 1, or decreasing with -1 in descending order. Then, in the return statement, we are using the sort function of the array itself, and we are sending as parameter the anonymous function to compare the mapped config.propertyName values in the config object.

This is how we are retrieving the data from some backend service:

import {HttpClient} from 'aurelia-http-client';

export class Example {
      users = [];
      activate() {
        return new HttpClient()
          .get('https://api.ourorganization.com/users')
          .then(response => this.users = response.content);
      }
}

There's nothing weird at this point. Now, let's check the View file:

<template>
      <require from="./array-sort"></require> <<-- Import your value converter

      <div class="row">
        <div class="col-sm-3" repeat.for="user of users | arraySorting: { propertyName: 'code', direction: 'descending' }">
            ${user.firstName}
          </a>
        </div>
      </div>
</template>

It's beautiful. We don't need to add any JavaScript function or weird configuration to start using this very useful functionality.

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

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