Вложенные представления и контроллеры EmberJS

Я пишу приложение с EmberJS v1.0.pre. У меня есть ArrayController, который содержит список всех лиц. Есть куча вложенных представлений, показывающих человека, их питомцев и заметки для каждого питомца.

|----------------------------------------|
| 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 ok              |
|                                        |
|----------------------------------------|
| ...                                    |

С чистой точки зрения MVC кажется, что для каждого ребенка должен быть контроллер, но я не могу понять, как это достичь в Ember. Существует верхний контроллер массива, а затем все отдельные виды. Если я хочу удалить заметку или отредактировать ее, мне кажется, что мне нужно передать контекст представления до контроллера.

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

Для меня это очень плохо, представление не должно быть авторитетным источником данных. Мое предположение заключается в том, что ArrayController создаст экземпляр itemControlerClass вместе с itemViewClass.

ОБНОВЛЕНИЕ: Я создал fiddle, чтобы лучше проиллюстрировать мою проблему. Функциональность преднамеренно неполна, цель состоит в том, чтобы закончить функциональность, увеличив содержание, когда щелкнул элемент в списке.

ОБНОВЛЕНИЕ: Извините, я удалил скрипку при аварии! Я делаю некоторую работу над окончательным решением, поэтому я попытаюсь создать новую скрипку с решением.

Ответ 1

"С чистой точки зрения MVC кажется, что для каждого ребенка должен быть контроллер"

Вам не нужен контроллер для каждого элемента, но вместо этого ArrayController для каждой коллекции объектов (People, Pets, Notes). Кстати, любые действия над дочерними объектами (собаки, заметки) не должны передаваться на App.PersonsController. Это нарушит принцип Разделение проблем..

Документы Ember.Router охватывают случай, когда вы хотите вложить представления в один объект (например, /:people_id). Но вы хотите вложить представления для массива объектов. Я не могу придумать способ вложенных представлений {{outlet}}, но вы можете сделать следующее:

Загрузите объекты People, Pets, Notes в 3 ArrayControllers и делегируйте действия дочерним объектам в соответствующий 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());
        }
    })
  })
});

И тогда ваш шаблон people должен выглядеть так:

{{#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}}

Как вы можете видеть, действия над дочерними объектами делегируются его контроллеру (pet → petsController), передавая объект в качестве контекста. В случае действия create, контроллер должен знать, кому принадлежит домашнее животное belongsTo. Поэтому мы передаем два контекста: человек и свойства домашнего животного (для простоты я принял только имя для домашнего животного).

В вашем App.petsControllers вы должны иметь действия по строкам:

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

Ответ 2

Вы должны использовать выходы. Они немного "заполнители" в представлениях Ember, которые можно обрабатывать с помощью разных контроллеров.

Существует справедливое объяснение по ссылке выше, где вы уже проверили и ничего не нашли. Но прежде чем вы вернетесь к этому, сначала прочтите это: http://trek.github.com/

Если какой-либо из них по-прежнему вам не поможет, сообщите об этом, и я соберу аккомпанемент для вас.

Ответ 3

Я думаю, это, что вы ищете, посмотрите, это довольно прямолинейно, вы также можете проверить this. В основном вы можете добиться того, что хотите, с выходами, маршрутизаторами и действиями для подключения всех ваших торговых точек.

Ответ 4

Я новичок в Ember и искал способ сделать что-то подобное. В ArrayController верхнего уровня я просто использовал свойство itemController, и он отлично работал:

App.PeopleController = Ember.ArrayController.extend({
    itemController: "Person"
});

App.PersonController = Ember.ObjectController.extend //...

Мое полное решение находится в этой js скрипке. К сожалению, способ, которым я получаю экземпляры PetController для работы, кажется мне взломанным.