Ember.JS - 如何在同一页面中使用多个模型、控制器和视图?

Posted

技术标签:

【中文标题】Ember.JS - 如何在同一页面中使用多个模型、控制器和视图?【英文标题】:Ember.JS - How to use multiple models, controllers and views in same page? 【发布时间】:2013-02-11 10:16:44 【问题描述】:

我主要了解 Ember.JS 的基础知识。那里的大多数示例实际上只处理单个控制器和模型以在页面上显示某些内容。我真的很想用 Ember 构建一个完整的 Web 应用程序,所以谁能告诉我如何将多个控制器、模型和视图组织和连接到一个页面中?

例如,如果我导航到 /app/posts,我想显示一个导航栏,其中包含一些内容,包括一些登录信息、一个用于搜索的边栏以及一个附加的控制器,以及列出的一堆帖子中间,也许是一个 Twitter 提要,在侧边栏上填充了一个 TwitterFeedController。

如何将一堆这些连接在一起。在 Ember.JS 中用自己的控制器和模型和视图实现“Sections”的基本方法是什么?

我知道有名为“网点”。当前的文档似乎没有提到它在应用程序模板中有一个主要的 outllet 。我在他们的公共 API 文档上也找不到定义(可能是盲目的......)。

提前致谢!

【问题讨论】:

【参考方案1】:

希望这个答案Example1 和这个答案Example2

<script type="text/x-handlebars" data-template-name="application">
    partial 'navbar'
    outlet   
    partial 'footer'
</script>

<script type="text/x-handlebars" data-template-name="_navbar">
    <div class="navbar navbar-inverse">
        <div class="navbar-inner">
            #linkTo "app" class="brand"unbound App.app_title/linkTo
            <ul class="nav">
                <li class="divider-vertical">
                    #linkTo "app"Home/linkTo
                </li>
                <li class="divider-vertical">
                    #linkTo "products"Products/linkTo
                </li>
            </ul>
        </div>
    </div>
</script>

<script type="text/x-handlebars" data-template-name="_footer">
    <div class="row">
        <div class="span12">
            &copy; 2013:1.0-pre4 - unbound App.contact 
        </div>
    </div>    
</script>

<script type="text/x-handlebars" data-template-name="app">
    <h2>Home</h2>
    <p>Bacon ipsum dolor sit amet tenderloin short ribs short loin meatball sausage chicken pastrami. Hamburger sausage tri-tip, bacon spare ribs bresaola short ribs chuck frankfurter shoulder. Fatback pork belly turducken, ham drumstick salami hamburger pork sausage. Jowl corned beef andouille shank boudin. Shankle salami corned beef, pastrami leberkas turducken venison shoulder fatback jowl ball tip ground round biltong andouille boudin.</p>
    <p>Biltong boudin turkey rump shankle ball tip, strip steak drumstick spare ribs. Cow short ribs leberkas swine sirloin shank drumstick rump hamburger frankfurter ham hock. Bresaola turkey bacon prosciutto salami jowl pancetta meatloaf ground round ball tip filet mignon kielbasa tongue chuck strip steak. T-bone leberkas beef ribs kielbasa shankle pork chop spare ribs chuck strip steak shoulder frankfurter turducken. Pork loin ham cow chicken boudin venison. Filet mignon cow jowl pig ball tip, meatball boudin leberkas ham short loin drumstick tenderloin venison chicken. Chuck beef filet mignon capicola shankle, fatback flank ham hock corned beef meatloaf short ribs bacon.</p>
</script>

<script type="text/x-handlebars" data-template-name="categories">
    <h2>Categories</h2>
    <p>Listing available products and services</p>
    <ul class="thumbnails">
    #each category in controller
        <li class="span3">
            <div class="thumbnail">
                <h4>category.name</h4>
                <img bindAttr src="category.imageUrl"  />
                #linkTo "products.category" category class="btn"
                    Details
                /linkTo
            </div>
        </li>
    else
        <li>Loading...</li>
    /each
    </ul>
    <hr />
</script>

<script type="text/x-handlebars" data-template-name="products">
    render categories
    outlet
</script>

<script type="text/x-handlebars" data-template-name="products/index">
    <h2>Products</h2>
    <ul class="thumbnails">
    #each product in controller
        <li class="span3">
            <div class="thumbnail">
                <h4>product.name</h4>
                <img bindAttr src="product.imageUrl"  />
                #linkTo "products.product" product class="btn"
                    Details
                /linkTo
            </div>
        </li>
    else
        <li>Loading...</li>
    /each
    </ul>
</script>

<script type="text/x-handlebars" data-template-name="products/product">
    <h4><em style="color: gray">Products</em>/<em style="color: gray">Category: category.name</em>/name</h4><br />
    <img bindAttr src="imageUrl" />
    $ price hahahahaha
</script>

<script type="text/x-handlebars" data-template-name="products/category">
    <h2>name</h2>
</script>

<script type="text/javascript" src="http://code.jquery.com/jquery-1.8.2.min.js"></script>
<script type="text/javascript" src="https://raw.github.com/wycats/handlebars.js/1.0.rc.2/dist/handlebars.js"></script>
<script type="text/javascript" src="https://raw.github.com/emberjs/ember.js/release-builds/ember-1.0.0-pre.4.js"></script>
<script type="text/javascript" src="https://raw.github.com/MilkyWayJoe/ember.js/master/ember.min.js"></script>


var BaseApp = Em.Application.extend(
    app_title: 'Auto Web Shop',
    contact: function() 
        if(this.get('link') !== '') 
            var html = '<a href="%@" target="_blank">%@</a>'
                       .fmt(this.get('link'), this.get('author'));
            return new Handlebars.SafeString(html);
         else 
            return this.get('author');
        
    .property('author', 'link') 
);

// Extensions - End

window.App = BaseApp.create(
    author: 'Your Name Here',
    link: 'https://twitter.com/torontoemberjs'
);

// Controllers - Begin

App.ShopController = Em.ArrayController.extend();
App.ProductsController = Em.ArrayController.extend();
App.ProductsIndexController = Em.ArrayController.extend();
App.CategoriesController = Em.ArrayController.extend();

// Controllers - End

// Routes - Begin

App.Router.map(function() 
    this.resource('app');
    this.resource('products', function() 
        this.route('product', path: 'product/:product_id');
        this.route('category', path: 'category/:category_id')
    );
);

App.ApplicationRoute = Em.Route.extend(
  setupController: function() 
      this.controllerFor('categories').set('model', App.Category.find());
  
);

App.ProductsIndexRoute = Em.Route.extend(
    model: function() 
        return App.Product.find();
    
);

App.IndexRoute = Em.Route.extend(
    redirect: function() 
        this.transitionTo('app');   
    
);

// Routes - End

// Models - Begin

// Defining a Data Store for the application from DS namespace
App.Store = DS.Store.extend(
    // Until Ember reaches 1.0, Ember-Data will use a revisions to 
    // alert developers about breaking changes to the API. At the time I'm 
    // writing this, Ember-Data is on revision 11. To find out more, go to:
    // https://github.com/emberjs/data/blob/master/BREAKING_CHANGES.md
    revision: 11,
    // Define your adapter. The Adapter is responsible to 'translate' the data from
    // your backend API into what Ember-Data needs in order for it to work. Ember-Data
    // comes with a REST Adapter and a Fixture Adapter, the later is very useful for 
    // debugging and for mocking up an application. This example uses the Fixture Adapter
    adapter: 'DS.FixtureAdapter'
);

App.Category = DS.Model.extend(
    name: DS.attr('string'),    
    imageUrl: DS.attr('string'),
    products: DS.hasMany('App.Product')
);

App.Product = DS.Model.extend(
    name: DS.attr('string'),
    imageUrl: DS.attr('string'),
    price: DS.attr('number'),
    category: DS.belongsTo('App.Category')
);

// Loading sample data
// Note that all fixtures have an `id` property. That's because Ember-Data needs your 
// models to have an Id, but you don't define it on your model classes.
App.Category.FIXTURES = [
    
        id: 1, 
        name: 'Air Conditioners', 
        imageUrl: 'http://img9.imageshack.us/img9/1207/howtoreplaceyourcarairc.jpg', 
        products: []
    ,
        
        id: 2,
        name: 'Tires', 
        imageUrl: 'http://img526.imageshack.us/img526/5290/r8wheel1ljpg0f089f10250.jpg', 
        products: []
    ,
    
        id: 3, 
        name: 'Brakes', 
        imageUrl: 'http://img651.imageshack.us/img651/5600/brakes.gif', 
        products: []
    ,
    
        id: 4,
        name: 'Exhausts', 
        imageUrl: 'http://img217.imageshack.us/img217/7366/carbon20fibre20exhaust2.jpg', 
        products: []
    ,
    
        id: 5, 
        name: 'Batteries', 
        imageUrl: 'http://img842.imageshack.us/img842/268/t2ec16nhjhqe9nzej50bqu7.jpg', 
        products: []
    ,
    
        id: 6,
        name: 'Wipers', 
        imageUrl: 'http://img145.imageshack.us/img145/3750/1208764x64.jpg', 
        products: []
    ,
    
        id: 7, 
        name: 'GPS', 
        imageUrl: 'http://img687.imageshack.us/img687/8899/kgrhqroifcpor3cm0bq1ufc.jpg',
        products: [701,702,703]
    , 
    
        id: 8,
        name: 'Windshields',
        imageUrl: 'http://img405.imageshack.us/img405/6826/windshield3thumb.jpg',
        products: []
    
];

App.Product.FIXTURES = [
    
        id: 201,
        name: 'Pirelli P4 Four Seasons',
        category: 2,
        price: 9999,
        imageUrl: 'http://img4.imageshack.us/img4/4372/pirellip4fourseasonslg.jpg'
    ,
    
        id: 701, 
        name: 'Tomtom Start 4.3" GPS (45TM)', 
        category: 7, 
        price: 12999, 
        imageUrl: 'http://img856.imageshack.us/img856/7471/seeq2501.jpg'
    ,
    
        id: 702, 
        name: 'Garmin nüvi 4.3" GPS (40)', 
        category: 7,
        price: 11999, 
        imageUrl: 'http://img27.imageshack.us/img27/5116/88121963.jpg'
    ,
    
        id: 703, 
        name: 'Magellan RoadMate 2230T 4.3" GPS ', 
        category: 7, 
        price: 14399, 
        imageUrl: 'http://img820.imageshack.us/img820/7981/36361380.png'
    
];

// Models - End



// Views - Begin

// Views - End

【讨论】:

谢谢。我最终弄清楚了 outlet named 以及路由器 v2 是如何真正将责任转移到 XxxRoute 类来让您填充这些的。您的示例进一步完善了我的理解:)。部分出口对我来说是一个新概念。 对于所有正在搜索的人来说,这是我发现非常有用的另一个很棒的 jsFiddle。这有多个命名的网点:jsfiddle.net/W2dE4/6 我还应该指出,如果一个资源是嵌套的,你可以只在顶部资源中有一个 outlet 并且嵌套的资源将被吸引到其中(比如 index/new/edit routes ) 自动。

以上是关于Ember.JS - 如何在同一页面中使用多个模型、控制器和视图?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Ember.js 按模型类型/对象值选择视图模板

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

如何在 Ember JS 中获取模型数据

Ember.js:如何保存模型

Ember.js:如何加载音频文件

ember.js 和服务器