为啥没有调用我的 ember.js 路由模型?

Posted

技术标签:

【中文标题】为啥没有调用我的 ember.js 路由模型?【英文标题】:Why isn't my ember.js route model being called?为什么没有调用我的 ember.js 路由模型? 【发布时间】:2013-03-18 17:06:15 【问题描述】:

我刚开始学习 Ember.js(购买了 PeepCode 截屏视频),并且从中学习得非常顺利,但是在尝试编写我的第一个 Ember 应用程序时遇到了问题。

这是(嵌套的)路由映射:

App.Router.map(function () 
    this.resource('bases',  path: '/' , function () 
        this.resource('base',  path: ':base_id' , function () 
            this.resource('places', function () 
                this.resource('place',  path: ':place_id' );
            );
        );
    );
);

这允许这样的网址:domain.com/#/yokota-ab-japan/places/4c806eabd92ea093ea2e3872

yokota-ab-japan 是基地的 id(日本的空军基地) 4c806eabd92ea093ea2e3872 是 Foursquare 上的场地 id

当places 路由被命中时,我通过调用foursquare api 来设置数据,遍历JSON 以创建一个App.Place 对象数组,然后返回该数组。

App.PlacesRoute = Ember.Route.extend(
    model: function () 
        var placesData = Ember.A();
        $.getJSON('https://api.foursquare.com/v2/venues/search?ll=35.744771,139.349456&query=ramen&client_id=nnn&client_secret=nnn&v=20120101',
            function (data) 
                $.each(data.response.venues, function (i, venues) 
                    placesData.addObject(App.Place.create( id: venues.id, name: venues.name, lat: venues.location.lat, lng: venues.location.lng ));
                );
            );

        return placesData;
    
);

这似乎运作良好。我使用此模板显示 placesData 数组:

<script type="text/x-handlebars" data-template-name="places">
    <div>
        #each place in controller
            #linkTo 'place' place
                place.name
            /linkTo
        /each
    </div>

    outlet
</script>

linkTo 链接到各个地点,我想在其中显示有关地点的更多详细信息。这是我设置的用于提取有关单个地点的数据、填充单个 App.Place 对象并返回它的路线:

App.PlaceRoute = Ember.Route.extend(
    model: function (params) 
        console.log('place route called');

        var place;
        $.getJSON('https://api.foursquare.com/v2/venues/' + params.place_id + '?client_id=nnn&client_secret=nnn',
            function (data) 
                var v = data.response.venue;
                place = App.Place.create( id: v.id, name: v.name, lat: v.location.lat, lng: v.location.lng );
            );

        return place;
    
);

我的问题是,PlaceRoute 在用户单击指向它的链接时不会被调用,但在此路由上刷新页面时它会被调用。

根据 PeepCode Ember.js 截屏视频(在视频中约 12:25),它指出“控制器很少调用数据,路由对象处理它”,所以我认为我的 ajax 是正确的在路由中调用(我在网上看到了很多不同的教程,但是自从 Peepcode 咨询了 Ember.js 的创建者后,我将它作为我的主要学习资源)。

如果这不正确,或者可以做得更好,请告诉我。

【问题讨论】:

【参考方案1】:

模型钩子上的 Ember 文档:

"你可以实现一个钩子来将 URL 转换为模型 路线。”

这解释了为什么只在页面刷新时调用模型挂钩。但这让很多人感到困惑:-)。因此,在这种情况下,这不是正确的钩子。我认为您应该在这种情况下使用 setupController 挂钩。试试这个:

App.PlaceRoute = Ember.Route.extend(
    setupController: function (controller, model) 
        console.log('place route called');

        var place;
        $.getJSON('https://api.foursquare.com/v2/venues/' + model.get('place_id') + '?client_id=nnn&client_secret=nnn',
            function (data) 
                var v = data.response.venue;
                place = App.Place.create( id: v.id, name: v.name, lat: v.location.lat, lng: v.location.lng );
            );

        controller.set("model", place);
    
);

额外的 2 美分我自己:当通过 URL/直接浏览器导航进入应用程序时,为什么模型挂钩刚刚执行?

Ember 假设,如果您使用 linkTo,则不一定要调用模型挂钩。在您的场所模板中,您使用#linkTo 'place' place place.name /linkTo。您正在将一个地点对象传递给您的路线。 Ember 假定这是您在执行模型挂钩时会得到的同一个对象。 因此,从 Embers 视图中无需调用模型挂钩。因此,如果您想在使用linkTo 时执行检索逻辑,请使用setupController hook

【讨论】:

感谢您的解释,有助于了解事情的运作方式。这是有道理的,因为我将它传递给place,它不会检查路线上的模型。在setupController中,如何从url中获取place_id? 啊,抱歉,虽然我在寻找它,但还没有看到您依赖于 params 对象。我想有可能获得对参数的访问权限,但我并不容易。为什么你需要再次进行 AJAX 调用,虽然你通过了这个地方?响应中是否涉及更多细节? 查看我的更新。在 setupController 中,您还可以访问通过 linkTo 传递的模型 :-) 这应该是基本的 ember 功能,我不知道为什么 ember 创建者认为所有数据都应该在主(列表)页面中 - 它效率不高。我觉得它对所有 ember 初学者来说都很困惑。 值得注意的是,如果您将 id 而不是完整记录传递给 link-to,则会调用模型挂钩。【参考方案2】:

强制 Ember 使用模型钩子;只需传递 id 而不是对象:

#link-to 'place' place.id
    place.name
/link-to

由于 Ember 不再知道哪个对象与给定 id 相关,Ember 将调用模型挂钩(因此数据将从服务器加载)。

【讨论】:

在我看来这应该是公认的答案,它为我节省了数小时徒劳的调试。我的用例可能很常见,它访问像/groups/:group_id 这样的路由,但将属于该组的用户加载为路由的模型,而不是组本身。这样我就可以直接使用 ember 数据对用户进行分页,因为 hasMany children 的分页目前充满了恐惧和危险。 我也强烈认为这应该是公认的答案,尽管公认的答案也是正确的。只是接受的那个感觉更像是一种解决方法,当这个以更自然的余烬方式解决问题时。【参考方案3】:

基于 mavilein 的回答,但更短且适用于带有 Ember Data 的 Ember CLI...

import Ember from 'ember';

export default Ember.Route.extend(
  setupController: function( controller, model ) 
    controller.set( "model", this.store.fetch( 'place', model.id ) );
  ,
);

另请注意,fetch 方法仅适用于 Ember Data 1.0.0-beta.12。

http://emberjs.com/api/data/classes/DS.Store.html#method_fetch

【讨论】:

以上是关于为啥没有调用我的 ember.js 路由模型?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 ember.js 访问嵌套索引路由中的父模型?

coffeescript 1.7 破坏了我的 ember.js 计算属性

如何在 Ember js 控制器功能测试中调用路由功能?

从组件更新路由模型

Ember JS 过渡到嵌套路由,其中​​所有路由都是视图中的动态段

Ember.js 不会自动绑定模型 RESTful 更改