Ember.js - Как мне настроить таргетинг выходов во вложенных / повторных представлениях и каковы лучшие практики для такого макета пользовательского интерфейса?

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

Кажется, торговые точки - лучший способ сделать это.

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

{{#each item in controller}}
      {{view App.ItemThumbView}}
{{/each}}

Правая боковая панель этого вида представляет собой выход, который изменяется в зависимости от выбора. Когда я выбираю элемент, я хотел бы отобразить список операций редактирования в шаблонном вложенном представлении, который при выборе отображает правильный пользовательский интерфейс редактирования через вложенную розетку.

по существу

+---------------------------------------------------+
|        Parent Pane
|
| +------------------------------+ +----------+
| |  Device Section              | | Sidebar  |
| |                              | | [Outlet] |
| |  +--------+ +---------+      | |          |
| |  | Dev 1  | |  Dev 2  |      | |          |
| |  |[outlet]| | [outlet]|      | +----------+
| |  +--------+ +---------+      |
| +------------------------------+ 
+--------------------------------------------------+

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

Как выбрать правильный выход для вложенного представления в Ember? (В лучшем случае мне кажется, что я могу поразить выход боковой панели, но не выход в шаблоне вложенного устройства.) И является ли это разумной структурой для реализации контекстных меню в ember?

* Для пояснения При моей текущей настройке каждый элемент устройства отображается с использованием одного и того же шаблона. Когда выбрано, выход боковой панели будет обновляться с метаинформацией некоторого устройства, в то время как выбранное представление устройства также будет подключать его выход к меню редактирования. Только один элемент устройства может иметь одновременно подключенную розетку редактирования.

Имеет ли смысл даже использовать здесь розетку, или я должен добавить условную логику в шаблон, чтобы при необходимости отобразить меню редактирования?

Обновите, чтобы переформулировать часть вопроса о лучших практиках:

Розетки, кажется, отлично подходят для развязки компонентов и создания перспективных вложений. Но сейчас кажется, что доступ к нужному выходу для вложенного представления немного затруднителен. Кроме того, если вы всегда знаете, какой компонент (компоненты) будет условно вложен в шаблон, проще всего просто жестко закодировать ваши представления. например:

// within template used for individual result-list items
{{#if condition }}
   {{view reusableSubView}}
{{/if} 

Каков предпочтительный угольный способ делать вещи здесь? Есть ли какие-либо накладные расходы на создание торговых точек, которые не всегда могут быть подключены постоянно?

1 ответ

Решение

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

Это потому, что вам нужен один надежный выход для цели в шаблоне, и, похоже, нет хорошего способа программно назвать имя выхода во время выполнения.

Кроме того, выход, на который вы надеетесь нацелиться, должен существовать где-то в родительском шаблоне во вложении маршрутизаторов, контроллеров и шаблонов визуализации, используемых для визуализации текущего состояния экрана. Если выход не был установлен родительским объектом маршрута, вы не можете надеяться нацелиться на него в своем маршруте конечного узла.

Позвольте мне объяснить на примере:

Поскольку изначально я задавал свой вопрос, наш пользовательский интерфейс изменился со списка устройств на список людей, но принцип остается тем же.

У меня есть список людей с их фотографиями, и их можно щелкнуть, чтобы показать дополнительную информацию рядом с их результатом.

У меня есть шаблон людей, который выглядит примерно так:

<script type="text/x-handlebars" data-template-name="people" >
    <h3>People in this group</h3>
    <div class="peeps">
        {{#each controller}}
             {{ view App.PersonView }}
             {{#if selected }}
                   <div class='too-personal'>
                   {{ outlet veryPersonalDetails }}
                   </div>
             {{/if}}
         {{/each}} 
    </div>
</script>

И шаблон человека, который вроде как это:

<script type="text/x-handlebars" data-template-name="person" >
        {{#linkTo person this}}
            <div data-desc="person-item" class="item">
                <div class="portrait">
                    <img class="avatar" {{bindAttr src="gravatarUrl"}}/>
                </div>
                <div class="statuslabel"><span {{bindAttr class=":label statusLabel"}}>{{statusText}}</span></div>
                <div class="cTitle">{{fullName}}</div>
            </div>
        {{/linkTo}}     </script>

И шаблон деталей с дополнительной информацией и опциями редактирования

<script type="text/x-handlebars" data-template-name="person/details" > 
various edit options    
</script>

При нажатии на результат пользователя мой маршрутизатор получает обновление URL-адреса и заглушки в шаблоне сведений в шаблон родительского участника. Мой роутер настроен примерно так:

App.Router.map(function() {
...
    this.resource('people', { path: '/people'}, function() {
        this.resource('person', { path: '/:person_id' },
            function() {
                this.route('details');
            }
        );
    });

});

С отдельными маршрутами:

App.PeopleRoute = Ember.Route.extend({
    model: function() {
        return App.People.find();
    },
    setupController: function(controller, model) {
        controller.set('content', model);
    }
});

App.PersonRoute = Ember.Route.extend({
    model: function(params) {
        return App.People.peepsById[params.person_id];
    },

    setupController: function(controller, model) {
        this._super(controller, model);
        var person = model;
// this block ensures that only one person has a selected status at a time
// ignore the overly-verbose code. I'm cleaning it up tomorrow 
        var ls = App.People.lastSelected;
        if (ls) {
            ls.set('selected', false);
        }
        person.set('selected', true);
        App.People.lastSelected = person;
        controller.set('content', model);
    },

    renderTemplate: function() {
        // person is actually stored in router 'context' rather than 'model'
        // omg!
        var x = this.controllerFor('personDetails').set('content', this.get('context'));
        this.render('person/details', { // render person/details
            into:'people', // into the people template
            outlet: "veryPersonalDetails", // at the veryPersonalDetails outlet
            controller: x // using the personDetails controller for rendering
        });

// additional rendering in sidebar outlet for testing
        this.render('person/details',{
            into:'people',
            outlet: "personDetails",
            controller: x
        });

        console.log("@@@ we did it!");
    }
});

Первоначально я пытался иметь выход в PersonView, но это не сработало, так как мой личный шаблон фактически отображался в маршруте людей. К тому времени, когда приложение достигает маршрута человека, контроллер уже отобразил всех людей в списке. Человек, на которого я хочу нацелиться, давно прошел мимо.

Благодаря тому, что маршрут выступил в качестве посредника между родительским и желаемым дочерними шаблонами, я смог осуществить это.

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

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

Другие вопросы по тегам