web-dev-qa-db-fra.com

EmberJS: Comment charger plusieurs modèles sur le même itinéraire?

Bien que je ne sois pas nouveau dans le développement Web, je suis assez nouveau dans les frameworks MVC côté client. J'ai fait quelques recherches et j'ai décidé d'essayer EmberJS. J'ai parcouru le guide TodoMVC et cela avait du sens pour moi ...

J'ai installé une application très basique; route d'index, deux modèles et un modèle. J'ai un script php côté serveur en cours d'exécution qui renvoie quelques lignes de base de données.

Une chose qui me dérange beaucoup est de savoir comment charger plusieurs modèles sur le même itinéraire. J'ai lu quelques informations sur l'utilisation d'un setupController mais je ne suis toujours pas clair. Dans mon modèle, j'ai deux tables que j'essaie de charger avec des lignes de base de données non liées. Dans une application Web plus traditionnelle, je venais d'émettre des instructions sql et de les boucler pour remplir les lignes. J'ai du mal à traduire ce concept en EmberJS.

Comment charger plusieurs modèles de données non liées sur le même itinéraire?

J'utilise les dernières Ember et Ember Data libs.

Mise à jour

bien que la première réponse donne une méthode pour le gérer, la deuxième réponse explique quand elle est appropriée et les différentes méthodes pour quand elle n'est pas appropriée.

74
Eric

Vous pouvez utiliser Ember.RSVP.hash pour charger plusieurs modèles:

app/routes/index.js

import Ember from 'ember';

export default Ember.Route.extend({
  model() {
    return Ember.RSVP.hash({
      people: this.store.findAll('person'),
      companies: this.store.findAll('company')
    });
  },

  setupController(controller, model) {
    this._super(...arguments);
    Ember.set(controller, 'people', model.people);
    Ember.set(controller, 'companies', model.companies);
  }
});

Et dans votre modèle, vous pouvez vous référer à people et companies pour obtenir les données chargées:

app/templates/index.js

<h2>People:</h2>
<ul>
  {{#each people as |person|}}
    <li>{{person.name}}</li>
  {{/each}}
</ul>
<h2>Companies:</h2>
<ul>
  {{#each companies as |company|}}
    <li>{{company.name}}</li>
  {{/each}}
</ul>

Il s'agit d'un Twiddle avec cet exemple: https://ember-twiddle.com/c88ce3440ab6201b8d58

93
Marcio Junior

IL FAUT SE MÉFIER:

Vous devez faire attention à savoir si le retour de plusieurs modèles dans votre modèle de crochet est approprié. Posez-vous cette simple question:

  1. Mon itinéraire charge-t-il des données dynamiques basées sur l'URL à l'aide d'un slug :id? c'est-à-dire this.resource('foo', {path: ':id'});

Si vous avez répondu oui

N'essayez pas de charger plusieurs modèles à partir du crochet modèle dans cette route !!! La raison réside dans la manière Ember = gère la liaison aux routes. Si vous fournissez un modèle lors de la liaison à cette route ({{link-to 'foo' model}}, transitionTo('foo', model)), il sautera le crochet du modèle et utilisera le modèle fourni. Ceci est probablement problématique car vous plusieurs modèles attendus, mais un seul modèle serait livré. Voici une alternative:

Faites-le dans setupController/afterModel

App.IndexRoute = Ember.Route.extend({
  model: function(params) {
    return $.getJSON('/books/' + params.id);
  },
  setupController: function(controller, model){
    this._super(controller,model);
    controller.set('model2', {bird:'is the Word'});
  }
});

Exemple: http://emberjs.jsbin.com/cibujahuju/1/edit

Si vous en avez besoin pour bloquer la transition (comme le fait le hook du modèle), renvoyez une promesse du hook afterModel. Vous devrez suivre manuellement les résultats de ce crochet et les connecter à votre contrôleur.

App.IndexRoute = Ember.Route.extend({
  model: function(params) {
    return $.getJSON('/books/' + params.id);
  },
  afterModel: function(){
    var self = this;
    return $.getJSON('/authors').then(function(result){
      self.set('authors', result);
    });
  }, 
  setupController: function(controller, model){
    this._super(controller,model);
    controller.set('authors', this.get('authors'));
  }
});

Exemple: http://emberjs.jsbin.com/diqotehomu/1/edit

Si vous avez répondu non

Allez-y, retournons plusieurs modèles à partir du crochet de modèle de l'itinéraire:

App.IndexRoute = Ember.Route.extend({
  model: function() {
    return {
           model1: ['red', 'yellow', 'blue'],
           model2: ['green', 'purple', 'white']
    };
  }
});

Exemple: http://emberjs.jsbin.com/tuvozuwa/1/edit

Si c'est quelque chose qui doit être attendu (comme un appel au serveur, une sorte de promesse)

App.IndexRoute = Ember.Route.extend({
  model: function() {
    return Ember.RSVP.hash({
           model1: promise1,
           model2: promise2
    });
  }
});

Exemple: http://emberjs.jsbin.com/xucepamezu/1/edit

Dans le cas de Ember Data

App.IndexRoute = Ember.Route.extend({
  var store = this.store;
  model: function() {
    return Ember.RSVP.hash({
           cats: store.find('cat'),
           dogs: store.find('dog')
    });
  }
});

Exemple: http://emberjs.jsbin.com/pekohijaku/1/edit

Si l'un est une promesse, et l'autre ne l'est pas, tout est bon, RSVP se contentera d'utiliser cette valeur

App.IndexRoute = Ember.Route.extend({
  var store = this.store;
  model: function() {
    return Ember.RSVP.hash({
           cats: store.find('cat'),
           dogs: ['pluto', 'mickey']
    });
  }
});

Exemple: http://emberjs.jsbin.com/coxexubuwi/1/edit

Mélanger et assortir et amusez-vous!

App.IndexRoute = Ember.Route.extend({
  var store = this.store;
  model: function() {
    return Ember.RSVP.hash({
           cats: store.find('cat'),
           dogs: Ember.RSVP.Promise.cast(['pluto', 'mickey']),
           weather: $.getJSON('weather')
    });
  }, 
  setupController: function(controller, model){
    this._super(controller, model);
    controller.set('favoritePuppy', model.dogs[0]);
  }
});

Exemple: http://emberjs.jsbin.com/joraruxuca/1/edit

149
Kingpin2k

J'utilise quelque chose comme la réponse fournie par Marcio, mais cela ressemble à ceci:

    var products = Ember.$.ajax({
        url: api + 'companies/' +  id +'/products',
        dataType: 'jsonp',
        type: 'POST'
    }).then(function(data) {
        return data;
    });

    var clients = Ember.$.ajax({
        url: api + 'clients',
        dataType: 'jsonp',
        type: 'POST'
    }).then(function(data) {
        return data;
    });

    var updates = Ember.$.ajax({
        url: api + 'companies/' +  id + '/updates',
        dataType: 'jsonp',
        type: 'POST'
    }).then(function(data) {
        return data;
    });

    var promises = {
        products: products,
        clients: clients,
        updates: updates
    };

    return Ember.RSVP.hash(promises).then(function(data) {
      return data;
    });  
3
la_antorcha

Si vous utilisez Ember Data, cela devient encore plus simple pour les modèles indépendants:

import Ember from 'ember';
import DS from 'ember-data';

export default Ember.Route.extend({
  setupController: function(controller, model) {
    this._super(controller,model);
    var model2 = DS.PromiseArray.create({
      promise: this.store.find('model2')
    });
    model2.then(function() {
      controller.set('model2', model2)
    });
  }
});

Si vous souhaitez uniquement récupérer la propriété d'un objet pour model2, utilisez DS.PromiseObject au lieu de DS.PromiseArray :

import Ember from 'ember';
import DS from 'ember-data';

export default Ember.Route.extend({
  setupController: function(controller, model) {
    this._super(controller,model);
    var model2 = DS.PromiseObject.create({
      promise: this.store.find('model2')
    });
    model2.then(function() {
      controller.set('model2', model2.get('value'))
    });
  }
});
2
AWM

La dernière version de JSON-API implémentée dans Ember Data v1.13 prend très bien en charge le regroupement de différentes ressources dans la même demande, si cela ne vous dérange pas de modifier vos points de terminaison API.

Dans mon cas, j'ai un point de terminaison session. La session se rapporte à un enregistrement utilisateur, et l'enregistrement utilisateur se rapporte à divers modèles que je souhaite toujours charger à tout moment. C'est assez agréable pour tout cela de venir avec une seule demande.

Une mise en garde par la spécification est que toutes les entités que vous renvoyez doivent être liées d'une manière ou d'une autre à l'entité principale reçue. Je crois que ember-data ne traversera les relations explicites que lors de la normalisation du JSON.

Pour d'autres cas, je choisis maintenant de différer le chargement de modèles supplémentaires jusqu'à ce que la page soit déjà chargée, c'est-à-dire pour des panneaux de données séparés ou autre, donc au moins la page est rendue aussi rapidement que possible. Ce faisant, il y a une certaine perte/modification avec l'état de chargement d'erreur "automatique" à prendre en compte.

2
aceofspades