Ember.js在等待数据时渲染模板

时间:2014-09-22 12:30:22

标签: ember.js

我使用jQuery getJSON在我的ember.js应用程序(ember 1.7.0)中获取数据。 加载数据时渲染模板有一个小问题。

这是我的第一个方法:

Parivar.Router.reopen({
    rootURL: '/account/'
});

Parivar.Router.map(function() {
    this.route('orders', { path: '/orders' });
    this.route('order', {path: '/orders/:number'});
});

Parivar.IndexRoute = Ember.Route.extend({
    beforeModel: function(){
        this.transitionTo('orders');
    }
});

Parivar.Order = Ember.Object.extend({});

Parivar.Order.reopenClass({
    findMine: function(params) {
        return $.getJSON('/api/orders/mine?page=' + params.page);
    },
    order: function(params) {
        return $.getJSON('/api/orders/' + params.number);
    }
});

Parivar.OrdersRoute = Ember.Route.extend({
    queryParams: {
        page: {
            refreshModel: true
        }
    },
    model: function(params) { return Parivar.Order.findMine(params); }
});

Parivar.OrderRoute = Ember.Route.extend({
    model: function(params) { return Parivar.Order.order(params); }
});

Parivar.ApplicationController = Ember.Controller.extend({
    renderHeader: function() {
        return this.get('currentRouteName') === 'orders';
    }.property('currentRouteName')
});

Parivar.OrdersController = Ember.ObjectController.extend({
    queryParams: ['page'],
    page: 1,
    needPaginate: function() {
        return this.get('model.pages') != 1;
    }.property('model.pages')
});

Parivar = Ember.Application.create({
    rootElement: '#ember_orders',
    LOG_TRANSITION: true,
    LOG_ACTIVE_GENERATION: true,
    LOG_VIEW_LOOKUPS: true,
    ready: function() {
        console.log("Ember.TEMPLATES: ", Ember.TEMPLATES);
    }
});

我需要模板(应用程序,订单,订单,标题和加载) 在application.hbs中:

{{#if renderHeader}}
    {{partial 'header'}}
{{/if}}
{{outlet}}

一切正常(我有一个很好的加载模板!),除了渲染标题模板。它仅在加载所有数据并且加载模板消失后才显示。但我想在加载应用程序后立即显示标题。

我的第二种方法是使用beforeModel钩子。我试图将标题模板渲染到名为outlet的那里。但我得到并且错误地说没有名称标题的插座。当beforeModel中的代码执行时,可能没有出口?

在我的第三次尝试中,我将Order类中的findMine更改为:

findMine: function(params) {
    var orders = Parivar.Order.create();
    Ember.$.getJSON('/api/orders/mine?page=' + params.page).then(function(result) {
        orders.setProperties(result);
    });
    return orders;
}

所以,我有空订单对象立即返回给应用程序,然后填充数据。 一切正常,除了我没有渲染我的加载模板,并显示用户"你没有订单"直到数据在订单对象中填充。所有这些都是由返回空订单对象引起的。

这是一个问题:如何在加载数据之前呈现标题模板,同时仍然有令人敬畏的加载'模板功能?

任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

首先,您需要了解加载子状态的工作原理。有关详细信息,请查看http://emberjs.com/guides/routing/loading-and-error-substates/

一般来说,对于beforeModelmodelafterModel未立即解决的路线,Ember将尝试查找是否存在loading路线水平。如果存在loading路由,则Ember将进入该路由,直到解析出所有模型挂钩。在您的情况下,如果您想在加载数据之前显示标题,则需要将标题放在orders模板之外。

有几种方法可以解决您的问题。

第一种方式 - 将标题放入应用程序模板

是否需要为所有页面显示标题?如果是这样,您可以将标题放在orders路线的上层路线模板中,即application模板。

application.hbs

{{partial 'header'}}
{{outlet}}

然后在orders路由model挂钩中您可以返回一个承诺,然后会触发loading路由。

第二种方式 - 使用嵌套路线

如果您的标题仅在orders路由中呈现,则可以在子路径中加载数据。 orders.index路线是一个好地方。

Parivar.Router.map(function() {
  // This will create index, loading, error sub-states under orders
  // Note the blank function is needed even in Ember 1.7.0
  this.resource('orders', function() {});
});

Parivar.OrdersIndexRoute = Em.Route.extend({
  model: function(params) {
    return Parivar.Order.findMine(params);
  }
});

将标题放在orders.hbs

{{#if renderHeader}}
  {{partial 'header'}}
{{/if}}
{{outlet}} {{! will render "orders.index" here }}

您还需要orders/loading.hbs来触发加载子状态。或者您可以覆盖路由的loading操作以实现您自己的加载逻辑。

可在此处找到jsbin示例:http://emberjs.jsbin.com/sawez/3/edit

第三种方式 - 在setupController中加载数据并使用PromiseProxyMixin

这对你的案子来说不是一个好方法所以我不会说很详细的事情。我们的想法是将setupController钩子和mixin Em.PromiseProxyMixin中的数据加载到您的控制器中,然后您可以在yoru控制器中使用isFulfilledisRejectedisPending属性来呈现不同的内容。有关如何使用Em.PromiseProxyMixin,您可以看到this API documentation