Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/402.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript EmberJS:如何在同一路线上加载多个模型?_Javascript_Ember.js_Rsvp.js - Fatal编程技术网

Javascript EmberJS:如何在同一路线上加载多个模型?

Javascript EmberJS:如何在同一路线上加载多个模型?,javascript,ember.js,rsvp.js,Javascript,Ember.js,Rsvp.js,虽然我对web开发并不陌生,但我对客户端MVC框架还是相当陌生的。我做了一些研究,决定尝试一下EmberJS。我浏览了TodoMVC指南,它对我很有意义 我已经设置了一个非常基本的应用程序;索引路线,两个模型和一个模板。我有一个运行的服务器端php脚本,它返回一些db行 有一件事让我非常困惑,那就是如何在同一条路线上加载多个模型。我已经阅读了一些关于使用setupController的信息,但我仍然不清楚。在我的模板中,我有两个表,我正试图用不相关的db行加载它们。在一个更传统的web应用程序中

虽然我对web开发并不陌生,但我对客户端MVC框架还是相当陌生的。我做了一些研究,决定尝试一下EmberJS。我浏览了TodoMVC指南,它对我很有意义

我已经设置了一个非常基本的应用程序;索引路线,两个模型和一个模板。我有一个运行的服务器端php脚本,它返回一些db行

有一件事让我非常困惑,那就是如何在同一条路线上加载多个模型。我已经阅读了一些关于使用setupController的信息,但我仍然不清楚。在我的模板中,我有两个表,我正试图用不相关的db行加载它们。在一个更传统的web应用程序中,我只需要向sql语句发出命令,然后循环它们来填充行。我很难将这个概念翻译成EmberJS

如何在同一路线上加载多个不相关数据模型?

我正在使用最新的余烬和余烬数据库

使现代化 虽然第一个答案给出了处理方法,但第二个答案解释了何时合适以及何时不合适的不同方法。

注意: 您需要注意在模型挂钩中返回多个模型是否合适。问自己一个简单的问题:

  • 我的路由是否使用slug
    :id
    基于url加载动态数据?即
    this.resource('foo',{path:':id'})
  • 如果你回答是 不要尝试从该路径中的模型挂钩加载多个模型原因在于余烬处理链接到路由的方式。如果在链接到该路由时提供模型(
    {{link to'foo'model}}
    转换到('foo',model)
    ),它将跳过模型挂钩并使用提供的模型。这可能是有问题的,因为您希望有多个模型,但只提供一个模型。这里有一个替代方案:

    setupController
    /
    afterModel
    例如:

    如果需要它来阻止转换(就像模型钩子一样),则从
    afterModel
    钩子返回一个承诺。您需要手动跟踪来自该钩子的结果,并将它们连接到控制器

    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'));
      }
    });
    
    例如:

    如果你的回答是否定的 继续,让我们从路线的模型挂钩返回多个模型:

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

    如果是需要等待的东西(例如对服务器的调用,某种承诺)

    例如:

    对于余烬数据

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

    如果一个是承诺,而另一个不是,这都是好的,RSVP会很乐意使用这个值

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

    混搭,玩得开心

    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]);
      }
    });
    

    示例:

    注意:对于Ember 3.16+应用程序,下面是相同的代码,但具有更新的语法/模式:

    下面是针对Ember<3.16的,尽管代码可以作为3.16+完全向后兼容,但编写旧代码并不总是有趣的


    您可以使用加载多个模型:

    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);
      }
    });
    
    <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>
    
    import Route from '@ember/routing/route';
    import { inject as service } from '@ember/service';
    
    export default class IndexRoute extends Route {
      @service store;
    
      async model() {
        let [people, companies] = await Promise.all([
          this.store.findAll('person'),
          this.store.findAll('company'),
        ]);
    
    
        return { people, companies };
      }
    
    }
    
    在模板中,您可以参考
    人员
    公司
    ,以获取加载的数据:

    app/templates/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);
      }
    });
    
    <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>
    
    import Route from '@ember/routing/route';
    import { inject as service } from '@ember/service';
    
    export default class IndexRoute extends Route {
      @service store;
    
      async model() {
        let [people, companies] = await Promise.all([
          this.store.findAll('person'),
          this.store.findAll('company'),
        ]);
    
    
        return { people, companies };
      }
    
    }
    
    人:
    
      {{{每个人都是{人}
    • {{person.name}
    • {{/每个}}
    公司:
      {{{#每个公司作为|公司}
    • {{company.name}
    • {{/每个}}

    这是对这个示例的一种玩弄:

    我使用了类似于Marcio提供的答案,但它看起来像这样:

        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;
        });  
    

    如果使用余烬数据,则对于不相关的模型,它会变得更简单:

    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)
        });
      }
    });
    
    如果只想检索
    model2
    的对象属性,请使用而不是:

    如果您不介意修改API端点,那么在Ember Data v1.13中实现的最新版本非常支持在同一请求中捆绑不同的资源

    在我的例子中,我有一个
    会话
    端点。会话与一个用户记录相关,用户记录与我始终希望加载的各种模型相关。这是非常好的,因为这一切来与一个请求

    每个规范的一个警告是,您返回的所有实体都应该以某种方式链接到正在接收的主实体。我相信在规范化JSON时,ember数据只会遍历显式关系


    对于其他情况,我现在选择延迟加载其他模型,直到页面已经加载为止,即对于单独的数据面板或其他情况,因此至少页面会尽快呈现。执行此操作时,将考虑“自动”错误加载状态的一些丢失/更改。

    获取接受的答案,并将其更新为Ember 3.16+

    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);
      }
    });
    
    <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>
    
    import Route from '@ember/routing/route';
    import { inject as service } from '@ember/service';
    
    export default class IndexRoute extends Route {
      @service store;
    
      async model() {
        let [people, companies] = await Promise.all([
          this.store.findAll('person'),
          this.store.findAll('company'),
        ]);
    
    
        return { people, companies };
      }
    
    }
    
    注意,建议不要使用setupController设置别名,因为它会混淆数据来自何处以及数据如何从路由流向模板

    因此,在模板中,您可以执行以下操作:

    <h2>People:</h2>
    
    <ul>
      {{#each @model.people as |person|}}
        <li>{{person.name}}</li>
      {{/each}}
    </ul>
    
    <h2>Companies:</h2>
    
    <ul>
      {{#each @model.companies as |company|}}
        <li>{{company.name}}</li>
      {{/each}}
    </ul>
    
    人:
    
      {{{#each@model.people as | person}}
    • {{person.name}
    • {{/每个}}
    公司:
      {{{#each@model.companys as | company}
    • {{company.name}
    • {{/每个}}

    只要路线中没有任何动态路段,这种方法就可以了。如果您有动态段,并且路由是通过
    {{link to'index'someModel}}
    输入的,那么模型钩子将被完全跳过,这将打破此示例。更可靠的方法是在总是运行的
    setupController
    中加载任何额外的模型。这正是我想要的@EoinKelly我实际上会在这里使用controller#afterModel事件,因为你可以从afterModel返回一个承诺,并期望它像model一样运行,除非afterModel不会被跳过。你如何访问setupcontroller中的动态段、参数或查询参数feom?@Eoin Kelly:你可以通过传递n ID(或slug)inste绕过它