【问题标题】:`needs` not waiting for data to be returned before rendering template`needs` 在渲染模板之前不等待数据返回
【发布时间】:2014-07-03 17:50:29
【问题描述】:

我正在尝试实现一个控制器 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 从来都不是真的。 IE。它会尝试在数据加载之前显示数据。

我的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

编辑2: 在执行@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 在渲染模板之前没有等待模型的承诺实现。不过,您必须以这种方式定义内容似乎很奇怪。有关如何处理此问题的任何见解?

Edit3:another thread为我回答的问题

【问题讨论】:

  • 你会展示你的路由器吗?并提及您实际到达的路线foo/bar/1
  • 我在上面编辑并添加了,@kingpin2k

标签: ember.js ember-data


【解决方案1】:

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

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

正如另一个快速说明,AppsIndexApps 的路由,当您的 url 包含孩子时,它不会被命中。例如

路由器

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

【讨论】:

  • 真有见地,谢谢!我需要能够显示apps,但不想用this.get('store').findAll('app') 替换CampaignsNew 模型,因为这样我就无法为Campaign 获取新记录。本质上,我正在创建一个Campaign,它将拥有一个属于它的App,我希望他们能够选择它。您对我如何实现我想要做的事情有什么建议吗?
  • 感谢您提供如此详细、格式正确的答案。
  • 附带问题:我应该使用ObjectController ArrayController 还是只使用Controller 在返回上述哈希值时?使用除了普通的Controller 之外的任何东西都会导致尝试将设置委托给对象代理的“内容”属性而未定义的错误。 @kingpin2k
  • 我举了一些什么时候使用的例子
  • 谢谢 - 我认为您错误地将相同的示例用于 Object 和 Array 控制器?正如您所说,我确实在实施setupController。您的回答似乎暗示我不应该使用Controller,而是使用ObjectController,因为我将模型设置为this.store.createRecord('campaign')apps 作为返回的数组。但是 Ember 会抛出错误 attempting to set the content property of object proxy whilst it's undefined。再次感谢您@kingpin2k,您提供了很多帮助。
猜你喜欢
  • 2016-04-30
  • 1970-01-01
  • 2017-11-16
  • 1970-01-01
  • 2019-12-31
  • 1970-01-01
  • 2014-11-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多