`needs`在渲染模板之前不等待返回数据

时间:2014-07-03 17:50:30

标签: ember.js ember-data

我正在尝试实现一个控制器needing另一个(CampaignsNew需要AppsIndex),看起来像

App.CampaignsNewController = Ember.Controller.extend({
   needs: ['appsIndex']
});

在我的CampaignsNew模板中,我通过

显示它
{{#if controllers.appsIndex.content.isUpdating}}
  {{view App.SpinnerView}}
{{else}}
  {{#each controllers.appsIndex.content}}
    {{name}}
  {{/each}}
{{/if}}

然而controllers.appsIndex.content.isUpdating永远不会成立。即它会在加载数据之前尝试显示数据。

我的AppsIndex路线已覆盖模型:

App.AppsIndexRoute = Ember.Route.extend({
  model: function(controller) {
    var store = this.get('store').findAll('app');
  }
  ...
});

如果我在CampaignsNew路线中添加相同的代码并将模板修改为eachcontroller.content,我就可以使用它。哪位对我说needs没有使用这条路线?如果我转到/apps页面并加载数据,然后导航到/campaigns/new页面,它也会有效。

我如何让它工作?谢谢!

修改 根据要求,我的路由器的相关部分:

App.Router.map(function() {
  this.resource('apps', function() {
    ...
  });

  this.resource('campaigns', function() {
    this.route('new');
  });
});

AppsIndex访问/appsCampaignsNew访问/campaigns/new

EDIT2: 在实施了@ kingpin2k的建议之后,我发现Ember正在抛出一个错误。以下是更新的文件和收到的错误。

App.CampaignsNewController = Ember.ObjectController.extend({
  pageTitle: 'New Campaign'
});

App.CampaignsNewRoute = Ember.Route.extend({
  model: function(controller) {
    return Ember.RSVP.hash({
      campaign: this.store.createRecord('campaign'),
      apps: this.store.find('app')
    });
    // return this.store.createRecord('campaign');
  },

  setupController: function(controller, model){
    controller.set('apps', model.apps);
    this._super(controller, model.campaign);
  }
});

Ember引发了这个错误:

Error while loading route: Error: Assertion Failed: Cannot delegate set('apps', <DS.RecordArray:ember689>) to the 'content' property of object proxy <App.CampaignsNewController:ember756>: its 'content' is undefined.

read online这是因为内容对象不存在。如果我这样设置:

App.CampaignsNewController = Ember.ObjectController.extend({
  content: Ember.Object.create(),
  ...
});

然后页面加载没有错误,当检查Ember Chrome扩展程序时,我可以看到数据已加载。但它没有在页面上显示。我想这是因为content对象存在,所以Ember没有等待模型的承诺在渲染模板之前完成。看起来很奇怪,你应该以这种方式定义内容。有关如何处理这个的任何见解?

编辑3:问题在another thread

中为我解答

1 个答案:

答案 0 :(得分:2)

根据您的路由器,apps不是campaigns/new的父级。

这意味着有人可以点击#/campaigns/new,Ember会点击ApplicationRouteCampaignsRouteCampaignsNewRoute来填充所请求网址的必要信息。使用需求作为控制器之间的通信方式实际上只在祖先模式中有意义(也就是与父母,祖父母等沟通)。

正如另一个快速记录,AppsIndexApps的路线,当您的网址包含儿童时,它不会被点击。 e.g。

路由器

this.resource('apps', function() {
  this.resource('chocolate', function(){
     .....
  });
});

网址被点击

#/apps/chocolate

将被击中的路线

ApplicationRoute
AppsRoute
ChocolateRoute
ChocolateIndexRoute

仅当您未指定资源的路径时才会触发索引路由,并且您正在访问该确切的资源(也就是没有超过该资源的任何内容)。

更新

您可以从特定的钩子返回多个模型:

App.FooRoute = Em.Route.extend({
  model: function(){  
    return Em.RSVP.hash({
      cows: this.store.find('cows'),
      dogs: this.store.find('dogs')
    });
  }
});

如果您希望主模型仍为奶牛,可以在setupController级别进行切换。

App.FooRoute = Em.Route.extend({
  model: function(){  
    return Em.RSVP.hash({
      cows: this.store.find('cows'),
      dogs: this.store.find('dogs')
    });
  },
  setupController: function(controller, model){
    controller.set('dogs', model.dogs);  // there is a property on the controller called dogs with the dogs
    this._super(controller, model.cows);  // the model backing the controller is cows
  }
});

在这里查看第二个答案,EmberJS: How to load multiple models on the same route?(第一个也是正确的,只是没有提到从模型钩子返回多个模型的问题)。

您也可以在setupController期间设置属性,但这意味着在页面加载时它将不可用,但稍后会异步。

哪个控制器?

如果您不打算使用型号支持控制器,请使用控制器。

App.FooRoute = Em.Route.extend({
  model: function(){
    return undefined;
  }
});

如果要将控制器的模型设置为某个集合,则使用ObjectController。

App.FooRoute = Em.Route.extend({
  model: function(){  
    return Em.RSVP.hash({
      cows: this.store.find('cows'),
      dogs: this.store.find('dogs')
    });
  }
});

如果某些东西将成为某种集合,请使用ArrayController。

App.FooRoute = Em.Route.extend({
  model: function(){  
    return ['asdf','fdsasfd'];
  }
});

注意

如果覆盖setupController,它将不会设置控制器的模型,除非您明确告诉它,或使用this._super

App.FooRoute = Em.Route.extend({
  model: function(){  
    return Em.RSVP.hash({
      cows: this.store.find('cows'),
      dogs: this.store.find('dogs')
    });
  },
  setupController: function(controller, model){
    controller.set('cows', model.cows);
    controller.set('dogs', model.dogs);
    // uh oh, model isn't set on the controller, it should just be Controller
    // or you should define one of them as the model
    // controller.set('model', model.cows); or
    // this._super(controller, model.cows); this does the default setupController method
    // in this particular case, ArrayController
  }
});