Working with asynchronous routing

A more advanced feature of the router is dealing with asynchronous logic. The following recipes explain this concept using promises.

How to do it...

In the route, Ember makes heavy use of promises. Promises are objects that represent an eventual value. We can use promises in our model.

  1. Create a new router for the application route:
    $ ember g route application
    

    If prompted to overwrite the template, type Y. This will generate the router file for the default application route.

  2. Add a new model to the application.js file in the app/router folder:
    // app/router/application.js
    import Ember from 'ember';
    
    export default Ember.Route.extend({
        model() {
          return  new Ember.RSVP.Promise(function(resolve) {
            resolve({message: 'Resolved'});
          });
        } ,
        setupController(controller, model){
          this._super(controller, model);
          console.log(model.message);
        }
    });

    In the router, we created a new model. This model will be accessible to our application template. In this model, we are returning Ember.RSVP.Promise, which is Ember's way of dealing with a promise. It can either resolve or reject. For the sake of simplicity, we are having it return a message.

    The setupController hook to set up the controller for the current route. As we are overwriting setupController, it also overwrites its default behavior. Therefore, we must call super on it. Otherwise it may effect how it normally behaves. We can use console.log to output the model message to the console.

    Tip

    Asynchronous routing

    During a transition, the model hook is fired in the router. If, during this transition, the model is returning an array, it will return immediately. On the other hand, if the model is returning a promise, it must wait for this promise to fulfill or reject. The router will consider any object with a then method defined on it to be a promise. After the promise fulfills, the transition will continue from where it left off. It's possible to chain multiple promises, so the next promise or model must be fulfilled before the transition will be complete.

  3. Let's edit the application router one more time and set it to reject:
    // app/routes/application.js
    import Ember from 'ember';
    
    export default Ember.Route.extend({
        model() {
          return Ember.RSVP.Promise.reject('error');
        },
        setupController(controller, model)
           this._super(controller, model);
           console.log(model.message);
        },
        actions: {
          error(reason){
            console.log(reason);
          }
        }
    });

    In the preceding code, the model returns a rejected promise. As described in the Loading and error handling recipe, there is something called an error event. This will fire only when an error occurs in the model. We can then log the error to the console.

  4. We can test this by editing the application.hbs file in the app/templates folder:
    // app/templates/application.hbs
    {{outlet}}
    
    Message: {{model.message}}

    If the promise doesn't reject, the model message will be displayed. If the model rejects, then nothing will be displayed; the route halts the loading and the console will show the message, error.

    Error events bubble upwards. In this case, we are already on the application route and it can't bubble up any further. If we were in another route, we could have returned true and that error would have bubbled up to the application error event.

  5. Edit the application.js file again in the app/router folder. Let's deal with the rejection:
    // app/routers/application.js
    import Ember from 'ember';
    
    export default Ember.Route.extend({
        model() {
          return new Ember.RSVP.Promise(function(resolve,reject) {
            reject('error');
          }).then(null, function() {
            return {message: 'Returned from rejection};
          });
        },
        setupController(controller, model){
          this._super(controller, model);
          console.log(model.message);
        },
        actions: {
          error(reason){
            console.log(reason);
          }
        }
    
    });

    In the preceding code, the RSVP promise rejects. However, we then return the message anyway, by chaining another promise at the end. This way the transition won't halt and will continue.

  6. Run ember server and open a web page. You should see this message:
    How to do it...

    This message shows Returned from rejection because we handled the promise reject callback and returned a message anyway.

How it works...

Promises are a way for Ember to handle asynchronous logic. A promise is an object that represents an eventual value. The promise can either reject or fullfill, as in resolve a value. To retrieve the value or handle when it rejects, you can use the then method, which can accept two different callbacks. The first is for fulfillment and the second is for rejection. For example, you might use the rejection to retry or return different data.

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

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