EmberJS嵌套视图和控制器 [英] EmberJS Nested Views and Controllers

查看:94
本文介绍了EmberJS嵌套视图和控制器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用EmberJS v1.0.pre编写一个应用程序。我有一个 ArrayController ,其中包含所有人的列表。有一堆嵌套的视图显示人,他们的宠物和每只宠物的笔记。

  | ----- ----------------------------------- | 
|约翰| < - Person
| ---------------------------------------- |
|昆西(狗)| < - Pet
| - 超人气| < - 注释
| - 喜欢XYZ狗食|
| - 会吃你的袜子|
| |
|汤姆(猫)|
| - 永远(不)捕捉老鼠|
| |
| ---------------------------------------- |
|罗杰|
| ---------------------------------------- |
| V(狗)|
| - 喜欢XYZ狗食|
| - 打喷嚏,但没关系
| |
| ---------------------------------------- |
| ... |

从纯MVC的角度来看,感觉就像每个孩子都应该有一个控制器,但是我可以'弄清楚如何在Ember中实现。有顶部的Array控制器,然后是所有的单独的视图。如果我想删除一个注释,或者编辑它,似乎我需要将视图的上下文传递给控制器​​。

  // in the view 
click:function(){
this.get('controller')。updateNote(this.get('content'))
}

这对我来说真的很糟糕,View不应该是数据的权威来源。我的假设是ArrayController将实例化 itemControlerClass 以及 itemViewClass



更新:我已经创建了一个小提琴,以更好地说明我的问题。该功能是故意不完整的,目的是通过在点击列表中的项目时增加内容来完成功能。



更新:对不起,我意外删除了小提琴!我正在做一些最终解决方案的工作,所以我将尝试用解决方案创建一个新的小提琴。

解决方案


从纯粹的MVC立场来看,每个孩子都应该有一个控制器


你不需要每个项目的控制器,而是需要每个对象集合(People,Pets,Notes)的ArrayController。顺便说一句,对孩子对象(狗,笔记)的任何操作都不应该传递给 App.PersonsController 。这将打破分离问题原则。



Ember。路由器文档覆盖了您想在单个对象中嵌套视图的情况(例如 /:people_id )。但是您希望嵌套对象数组的视图。我想不出有一种方式来嵌套 {{outlet}} 视图,但您可以执行以下操作:



在3 ArrayController中加载对象People,Pets,Notes,并将对象的操作委托给其对应的ArrayController。

 应用程序.Router = Ember.Router.extend({
root:Ember.Route.extend({
route:'/',
persons:Ember.Route.extend({
connectOutlets:function(router){

router.get('applicationController')。connectOutlet('persons');
// App.Note.find()获取所有Notes,
//如果您没有使用ember数据,请确保笔记已加载到notesController
router.set('notesController.content',App.Note.find());
路由器。 set('petsController.content',App.Pet.find());
}
})
})
});

然后您的人员模板应该看起来像:

  {{#每个人在人物}} 
< h1>我的名字是{{person.name }}< / H1>

{{#each pet in person.pets}}
我有一个宠物名字{{pet.name}}
< a {{action delete pet target = App.router.petsController>删除宠物< / a>
{{/ each}}

{{view Ember.TextField valueBinding =myNewPetNametype =text}}
< a {{action create myNewPetName person target = 控制器}}>
为这个人添加一个新的宠物
< / a>


{{#each note in person.notes}}
<! - 删除,创建,编辑... - >
{{/ each}}

如您所见,对象的操作是委托给其控制器(宠物 - > petsController),将对象作为上下文传递。在创建操作的情况下,控制器需要知道宠物属于哪个人。因此,我们通过了两个环境:人和宠物的属性(为了简单起见,我只假定宠物的名字)。



在您的App.petsController中,您应该采取以下行动:

  App.PetsController = Ember.ArrayController.extend({
delete:function(e){
var context = e.context;
this.get('content')。removeObject上下文);
//另外,如果使用ember-data,
// App.Pet.deleteRecord(context);
},

create:function (e){
var petName = e.contexts [0]
var person = e.contexts [1];
this.get('content')。pushObject({name:petName ,person:person});
//与ember-data:
// App.Pet.createRecord({name:petName,person:person});
}
});


I'm writing an app with EmberJS v1.0.pre. I have an ArrayController which contains a list of all persons. There are a bunch of nested views showing the person, their pets and the notes for each pet.

|----------------------------------------|
| John                                   | <- Person
|----------------------------------------|
|   Quincy (Dog)                         | <- Pet
|     - Super ornery                     | <- Note
|     - Likes XYZ Dog food               |
|     - Will eat your socks              |
|                                        |
|   Tom (Cat)                            |
|    - Always (not) catching mice        |
|                                        |
|----------------------------------------|
| Roger                                  |
|----------------------------------------|
|   V (Dog)                              |
|    - Likes XYZ Dog food                |
|    - Sneezes, but it's ok              |
|                                        |
|----------------------------------------|
| ...                                    |

From the pure MVC standpoint it feels like there should be a controller for each child, but I can't figure out how to achieve that in Ember. There is the top Array controller and then all the individual views. If I want to delete a note, or edit it, it seems like I need to pass the view's context up to the controller.

// in the view
click: function () {
  this.get('controller').updateNote(this.get('content'))
}

This feels really bad to me, the View is not supposed to be the authoritative source for data. My assumption is that an ArrayController would instantiate an itemControlerClass along with the itemViewClass.

UPDATE: I have created a fiddle to better illustrate my problem. The functionality is intentionally incomplete, the purpose is to finish the functionality by increasing the content when an item on the list is clicked.

UPDATE: Sorry, I deleted the fiddle on accident! I'm doing some work on a final solution, so I'll try to create a new fiddle w/ the solution.

解决方案

"From the pure MVC standpoint it feels like there should be a controller for each child"

You don't need a controller for each item, but instead an ArrayController for each collection of objects (People, Pets, Notes). By the way, any actions on child objects (dogs, notes) shouldn't be passed to App.PersonsController. That would break the Separation of Concerns principle.

Ember.Router docs cover the case where you want to nest views in a single object ( e.g. /:people_id). But you want to nest views for an array of objects. I can't think of a way to nest {{outlet}} views, but you can do the following:

Load the objects People, Pets, Notes in 3 ArrayControllers, and delegate actions on child objects to its corresponding ArrayController.

App.Router = Ember.Router.extend({
  root: Ember.Route.extend({
    route: '/',
    persons: Ember.Route.extend({
        connectOutlets: function(router) {

          router.get('applicationController').connectOutlet('persons');
          // App.Note.find() fetches all Notes,
          // If you are not using ember-data, make sure the notes are loaded into notesController
          router.set('notesController.content', App.Note.find());
          router.set('petsController.content', App.Pet.find());
        }
    })
  })
});

And then your people template should look like:

{{#each person in people}}
  <h1>My name is {{person.name}}</h1>

  {{#each pet in person.pets}}
     I have a pet with name {{pet.name}}
     <a {{action delete pet target="App.router.petsController">Delete pet</a>
  {{/each}}      

  {{view Ember.TextField valueBinding="myNewPetName" type="text"}}
  <a {{action create myNewPetName person target="controller"}}>
    Add a new pet for this person
  </a>


  {{#each note in person.notes}}
    <!-- delete, create, edit ... -->
  {{/each}}

As you can see, the actions on child objects are delegated to its controller (pet -> petsController), passing the object as the context. In the case of the create action, the controller needs to know to which person the pet belongsTo. Therefore we pass 2 contexts: the person, and the properties of the pet (for simplicity I assumed just a name for the pet).

In your App.petsControllers you should have actions along the lines:

App.PetsController = Ember.ArrayController.extend({
   delete: function(e) {
     var context = e.context;
     this.get('content').removeObject(context);
     // Also, if you use ember-data,
     // App.Pet.deleteRecord(context);
   },

   create: function(e) {
     var petName = e.contexts[0]
     var person = e.contexts[1];
     this.get('content').pushObject({name: petName, person: person});
     // with ember-data:
     // App.Pet.createRecord({name: petName, person: person});
   }
});  

这篇关于EmberJS嵌套视图和控制器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆