2013-04-20 3 views
21

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

Например:

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

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

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

<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:

Большое спасибо Brandon Тилли для объяснения опасности использования областей в качестве моделей. Но я все еще часто нахожу необходимость в некоторой быстрой декларативной манипуляции с областью и желаю директивы 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> 

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

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

ответ

10

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

Miško Hevery, автор AngularJS, делает хорошую работу, объясняя эту концепцию в this video, starting at about the 30 minute mark and lasting about 3 minutes:

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

Хотя это может быть возможным, чтобы написать ngWith директивы, которая делает вид, что вы ищете, так как Угловые использует прототипичное наследование областей, вы, вероятно, столкнутся с теми же проблемами, что Miško описывает в вышеупомянутом video at 31:10 (где вы думаете, что обновляете значение в родительской области, но на самом деле нет). Для получения дополнительной информации о прототипном наследовании в AngularJS ознакомьтесь с замечательной статьей The Nuances of Scope Prototypal Inheritance на вики-странице AngularJS.

+1

Отличный ответ. Я не видел этого видео. – nicholas

+3

Я вижу, что директива ng-with используется для других вещей, например, для хранения вывода дорогостоящего вызова метода модели EG:

{{best.name}} {{best.value}} {{best.price}}
... (создание неявной одноразовой области без необходимости создания целого контроллера) У вас есть см. какие-либо недостатки? Это заставляет меня задаться вопросом, почему ngWith не является базовой директивой в угловом –

+0

. Извлекающее правило большого пальца от видео: «Всякий раз, когда у вас есть ng-модель, там где-то есть точка. Если у вас нет точки, вы делаете это неправильно. –

21

Я нашел, что могу просто поместить массив вокруг источника 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> 

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

+0

Мне было бы интересно услышать недостатки этого подхода, поскольку я думаю, что его гениальность и становится очень полезной для меня. Спасибо, это лучшее решение, которое я нашел до сих пор, и делает именно то, что ищет OP. – Tony

+0

Я не эксперт в области углового исполнения. Но я не заметил ничьей. – Harry

+0

Удивительно, да, я тоже. Этот метод отлично работает и должен быть ответом :) Не могу сделать это легче! – Tony

4

Другой подход должен были бы установить новую переменный с помощью 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> 
+0

Единственная разница между этим и 'with' заключается в том, что вы должны указать имя базовой переменной; в вашем примере, 'name'. Я могу принять это (на самом деле это облегчает чтение). +1. –

+0

Также имейте в виду, что в моем случае переменная 'name' расширяет область действия вне блока. Это то же поведение, что и для 'var name;': это область функций, а не область блока. – kernel

0

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

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

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

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

Смежные вопросы