Подтвердить что ты не робот

Должна ли существовать директива AngularJS ngWith?

Возможно, я сумасшедший или слишком привык к KnockoutJS, но я продолжаю искать директиву ngWith в документах для определения области действия элемента, в контроллере или для частичного включения (ngInclude).

Например:

Я бы хотел написать контроллер, который добавляет MyItem:

MyModule.controller('MyItemCtrl', function($scope) {
    $scope.doSomethingToItem = function() {
        $scope.name = "bar";
    };
});

Или представление/шаблон для MyItem like:

<div ng-controller="MyItemCtrl">
    {{name}}
    <button ng-click="doSomethingWithItem()">Do Something</button>
</div>

Но в обоих случаях я предполагаю, что моя $scope будет прототипически унаследована от моей модели MyItem.

Но область не наследуется от модели!!

Что меня озадачивает.

Вместо этого моя модель является свойством в области.

В случае ретранслятора:

<div ng-repeat="item in list">
    <div ng-controller="MyItemCtrl">
        {{item.name}}
        <button ng-click="doSomethingWithItem()">Do Something</button>
    </div>
</div>

что означает, что везде я должен использовать item.this или item.that вместо this и that. Я должен помнить, какие функции являются родными для модели и которые были применены непосредственно к сфере действия контроллером.

Если я хочу иметь частичное отображение имен (тупой пример, я знаю, но вы понимаете):

<h3>{{name}}</h3>

Мне нужно написать его

<h3>{{item.name}}</h3>

а затем убедитесь, что модель всегда является элементом. Обычно, обертывая его в директиве, просто определяет область действия с свойством item.

То, что я часто чувствую, что хочу сделать, просто:

<div ng-include="'my/partial.html'" ng-with="item"></div>

или

<div ng-repeat="list" ng-controller="MyItemCtrl">            
    {{name}}
    <button ng-click="doSomethingWithItem()">Do Something</button>
</div>

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

Спасибо.

EDIT:

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

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

<ul>
    <li ng-repeat="item in items" ng-click="selection = item">{{item.minView}}</li>
</ul>
<div ng-controller="ItemController">
    {{selection.maxView}}
</div>

теперь вам нужно получить свойства выбранного элемента, используя selection.property, а не то, что я хочу: item.property. Мне также пришлось бы использовать selection в ItemController! Составляя это полностью вместе с этим представлением.

Я знаю, в этом простом примере я мог бы иметь контроллер упаковки, чтобы он работал, но это иллюстрирует эту точку.

Я написал очень базовую директиву with:

myApp.directive('with', ['$parse', '$log', function(parse, log) {

    return {
        scope: true,
        link: function(scope, el, attr) {
            var expression = attr.with;
            var parts = expression.split(' as ');

            if(parts.length != 2) {
                log.error("`with` directive expects expression in the form `String as String`");
                return;
            }

            scope.$watch(parts[0], function(value) {
                scope[parts[1]] = value;
            }, true);
        }
    }

}]);

который просто создает новую область, анализируя одно выражение на другое значение, позволяя:

<ul>
    <li ng-repeat="item in items" ng-click="selection = item">{{item.minView}}</li>
</ul>
<div with="selection as item" ng-controller="ItemController">
    {{item.maxView}}
</div>

Это кажется мне бесконечно полезным.

Я что-то упустил? Просто как-то беспокоиться о себе?

4b9b3361

Ответ 1

Это отличный вопрос. Я вижу, как это может сбивать с толку из другой инфраструктуры front-end, но в Angular область действия имеет ссылку на модель, и описанный вами синтаксис является нормальным. Мне лично нравится описывать область как более похожую на модель просмотра.

Miško Hevery, автор AngularJS, неплохо объясняет эту концепцию в этом видео, начиная примерно с 30-минутной отметки и продолжающейся около 3 минут:

Люди часто думают, что область действия является моделью, и это не так. Область имеет ссылки на модель. [...] Итак, вы видите model dot любое свойство, к которому вы хотите получить доступ.

В то время как может быть возможно написать директиву ngWith, которая делает вид того, что вы ищете, поскольку Angular использует прототипное наследование для областей, вы, вероятно, столкнетесь с теми же проблемами, которые Мишко описывает в вышеупомянутое видео в 31:10 (где вы думаете, что обновляете значение в родительской области, но на самом деле нет). Для получения более подробной информации о прототипном наследовании в AngularJS ознакомьтесь с отличной статьей Нюансы прототипного наследования на вики-странице AngularJS.

Ответ 2

Я нашел, что могу просто поместить массив вокруг источника ng-repeat, и он становится функционально ng-с.:)

<div ng-repeat="name in [vm.dto.Person.Name]" >
  <input type="text" ng-model="name.First" />
  <input type="text" ng-model="name.Last" />
</div> 

Кажется, что некоторые чисты могут не понравиться... Также не кажется, что есть хорошая альтернатива.

Ответ 3

Другим подходом было бы установить новую переменную через ng-init:

<div ng-init="name = vm.dto.Person.Name" >
  <input type="text" ng-model="name.First" />
  <input type="text" ng-model="name.Last" />
</div>

Ответ 4

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

И, конечно, приятно иметь возможность просто ссылаться на что-то в модели представления компонентов, не задумываясь о том, в какой области вы находитесь. И вы не можете сказать мне, что вы пропустите $parents[2] и $root; -)

PS. Да, я знаю, что вы можете использовать let в нокауте, что означает меньше $.

Я определенно пропускаю нокаут при работе с Angular (я все еще использую оба), но я уверен, что делать некоторые вещи вроде title="Customer #{{ row.customerId }} - {{ row.fullName }}" и не иметь все под data-bind.