Emberjs : how to display loading spinner and notif

2019-04-08 08:57发布

问题:

I am using ember.js 1.2 and facing a problem while trying to display loading spinner and notification messages during the crud operations on my models.

Here is the code :

var MyModelController = Ember.ObjectController.extend({
  needs: ['application'],
  application: Ember.computed.alias("controllers.application"),
  actions: {
    save: function() {
      var _this = this;

      // Display the spinner
      this.get('application').get('loading').trigger(true);

      this.get('model').save().then(function(response) {
        // Hide the spinner
        _this.get('application').get('loading').trigger(false);

        // Display the success message
        _this.get('application').get('flash').success('The model has been updated.');
      }, function(response) {
        // Hide the loading spinner
        _this.get('application').get('loading').trigger(false);

        // Display the error message
        _this.get('application').get('flash').danger('Error updating the model.');
      });
    }
  }
});

Two main problems here :

  • First : the spinner is displayed with a translation that takes 0.5s but the save operation is performed with less duration and the spinner is displayed and disappears immediately. Here I would like to set a 1s timer before the save operation is called on my model to ensure the animation is performed correctly. How could it be possible ?

  • Second : the success method on my flash object is binded to the specific {{view.message}} on the template. If I call this method outside the 'then' of the promise, the message is well displayed, but in my case it is not as if the binding is not done. Did I miss something in the way to use the promise ? How could it be possible to display this message ?

回答1:

You'll want to implement a loading route

http://emberjs.com/guides/routing/loading-and-error-substates/

https://gist.github.com/machty/6944577



回答2:

Concerning the loading spinner : kingpin2k gave a way to a solution. The legacy LoadingRoute is called when a promise is taking to many time to return. So I wrote it this way :

var ApplicationRoute = Ember.Route.extend({
  actions: {
    loading: function() {
      var _app = this.controllerFor('application');
      _app.get('loading').trigger(true);
      this.router.one('didTransition', function() {
        _app.get('loading').trigger(false);
      });
    }
  }
});

Then in the routes I forced my promises to take at least 500ms before returning. So the animation spinner appears and the UI is correctly updated.

model: function() {
  var _this = this;
  return new Ember.RSVP.Promise(function(resolve) {
    setTimeout(function() {
      resolve(_this.get('store').find('model'));
    }, 500);
  });
},

This way works for fetching data through the model hook of the route. But for updating a model from a save button, I wrote a specific ModelController that implements the save action ; then all my controllers that manage a single resource extend it :

var ModelController = Ember.ObjectController.extend({
  needs: ['application'],
  updateOKMessage: null,
  updateKOMessage: null,
  application: Ember.computed.alias("controllers.application"),
  actions: {
    save: function() {
      var _this = this;
      var _app = _this.get('application');

      // Display the loading spinner
      _app.get('loading').trigger(true);

      // Wait during 500ms to let the animation occurs
      setTimeout(function() {

        // Save the model
        _this.get('model').save().then(function(response) {
          setTimeout(function() {
            // Set the message of the flash from a timeout
            // if not, the message does not appear
            _app.get('flash').success(_this.get('updateOKMessage'));
          }, 100);
        }, function(response) {
          setTimeout(function() {
            // Same issue (or maybe it is not an issue)
            _app.get('flash').danger(_this.get('updateKOMessage'));
          }, 100);
          if(response.status === 422) {
            _this.get('model').set('errors', response.responseJSON.errors);
          }
        }).then(function() {
          setTimeout(function() {
            _app.get('loading').trigger(false);
          }, 600);
        });
      }, 500);
    }
  }
});

I corrected the problem with the flash messages setting them from a timer callback instead of from the promise's return method.



回答3:

my solution was quite simple and not the 'ember' way i suppose. but it works nice and doesn't spawn too many new files/helpers:

app/routes/application.js

import Ember from 'ember';

export default Ember.Route.extend(Ember.Evented, {
  actions: {
    loading: function() {
      // enable/disable spinner when model is loading slow
      Ember.$('#blur').css('-webkit-filter', 'blur(3px)')
      Ember.$('#spinner').css('display', 'flex')
      this.router.one('didTransition', function() {
        Ember.$('#blur').css('-webkit-filter', 'blur(0px)')
        Ember.$('#spinner').css('display', 'none')
      });
    }
  }
});