Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 10.02.2014, 17:12
Профессор
Отправить личное сообщение для Shitbox2 Посмотреть профиль Найти все сообщения от Shitbox2
 
Регистрация: 04.10.2010
Сообщений: 571

Доступ к scope формы из директивы
http://plnkr.co/edit/M7DNGAbDXQeLRslDIYs5?p=info

Почему свойства элементов контроллера формы не работают в директиве? Как сделать, чтобы Test.pass.$pristine было связано с полем ввода?

Нужно именно $pristine элемента, а не всей формы. Задавать имя напрямую в шаблоне директивы нельзя.
Ответить с цитированием
  #2 (permalink)  
Старый 10.02.2014, 21:17
Аватар для nerv_
junior
Отправить личное сообщение для nerv_ Посмотреть профиль Найти все сообщения от nerv_
 
Регистрация: 29.11.2011
Сообщений: 3,924

Сообщение от Shitbox2
Почему свойства элементов контроллера формы не работают в директиве?
Предполагаю, что объект, связанный с формой создается после создания DOM. Когда именно, сказать не могу
__________________
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук
Ответить с цитированием
  #3 (permalink)  
Старый 11.02.2014, 09:29
Аватар для FireVolkhov
Аспирант
Отправить личное сообщение для FireVolkhov Посмотреть профиль Найти все сообщения от FireVolkhov
 
Регистрация: 17.04.2013
Сообщений: 88

Дело в том, что dom содержимое директивы компилится раньше модели в рут элементе, в результате переписывается ссылка на контроллер модели в контроллере формы.

Результат сборки директивы
<div name="name" ng-model="model">
  <input name="name" ng-model="model">
</div>


Код в angular'e v1.2.11, отвечающий за добавление контроллера.
/**
   * @ngdoc function
   * @name ng.directive:form.FormController#$addControl
   * @methodOf ng.directive:form.FormController
   *
   * @description
   * Register a control with the form.
   *
   * Input elements using ngModelController do this automatically when they are linked.
   */
  form.$addControl = function(control) {
    // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
    // and not added to the scope.  Now we throw an error.
    assertNotHasOwnProperty(control.$name, 'input');
    controls.push(control);

    if (control.$name) {
      form[control.$name] = control;
    }
  };


Сначала добавиться контроллер из инпута, потом его перепишет контроллер из дива.

Решение
1. Удалить при компиляции атрибут name http://plnkr.co/edit/NpOoWQFTtOo0ICpXm9kL?p=preview
2. Использовать вместо ng-model, какой либо другой атрибут http://plnkr.co/edit/Yj42bdG0DwWdiShboF3T?p=preview
Ответить с цитированием
  #4 (permalink)  
Старый 11.02.2014, 12:39
Профессор
Отправить личное сообщение для Shitbox2 Посмотреть профиль Найти все сообщения от Shitbox2
 
Регистрация: 04.10.2010
Сообщений: 571

Да, совсем забыл, что директива при замене складывает атрибуты исходного элемента с атрибутами элемента шаблона. Получалось, что у нас два элемента с одинаковыми именами.

Если не задавать ng-model, то у заменяемой директивы не появится и ngModelController, соответственно, единственный оставшийся контроллер будет у внутреннего инпута и возьмется его имя.

Всё логично!
Ответить с цитированием
  #5 (permalink)  
Старый 11.02.2014, 13:54
Профессор
Отправить личное сообщение для Shitbox2 Посмотреть профиль Найти все сообщения от Shitbox2
 
Регистрация: 04.10.2010
Сообщений: 571

Первый способ больше нравится, т.к. пользователю очевиднее задавать модель в ng-model. Проблема в том, что добавляется еще один ngModelController, который участвует в валидации. Поэтому, на родительском диве также формируются классы ng-pristine и т.п., и сообщение об ошибке валидации может дублироваться.

Решил проблему установкой
terminal: true,
priority: 200

Но не до конца понимаю механизм приоритетов. Правильно ли сделал. Кто-нибудь может объяснить?

.directive('formPassword', function() {
        return {
            restrict: 'AE',
            terminal: true,
            priority: 200,
            templateUrl: 'template.html',
            replace: true,
            scope: {
                model: '=ngModel'
            },
            compile: function(tElem, tAttrs) {
                var input = tElem.find('input')[0];

                for (var k in tAttrs.$attr) {
                    if (tAttrs.$attr.hasOwnProperty(k)) {
                        if (k !== 'formPassword' && k !== 'type') {
                            input.setAttribute(tAttrs.$attr[k], tAttrs[k]);
                        }
                        if (k !== 'ngModel' && k !== 'class') {
                            tElem.removeAttr(tAttrs.$attr[k]);
                            delete tAttrs.$attr[k];
                            delete tAttrs[k];
                        }
                    }
                }

                return function(scope, element, attrs, ctrls) {
                    scope.show = false;
                }
            }
        };
    });
Ответить с цитированием
  #6 (permalink)  
Старый 12.02.2014, 10:27
Аватар для FireVolkhov
Аспирант
Отправить личное сообщение для FireVolkhov Посмотреть профиль Найти все сообщения от FireVolkhov
 
Регистрация: 17.04.2013
Сообщений: 88

Механизм прост, после сбора всех директив с ноды, angular сортирует их через функцию
/**
     * Looks for directives on the given node and adds them to the directive collection which is
     * sorted.
     *
     * @param node Node to search.
     * @param directives An array to which the directives are added to. This array is sorted before
     *        the function returns.
     * @param attrs The shared attrs object which is used to populate the normalized attributes.
     * @param {number=} maxPriority Max directive priority.
     */
    function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
...
      directives.sort(byPriority);
      return directives;
    }

/**
 * Sorting function for bound directives.
 */
    function byPriority(a, b) {
      var diff = b.priority - a.priority;
      if (diff !== 0) return diff;
      if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
      return a.index - b.index;
    }


A флаг terminal заставляет оборвать цикл применения директив, тем самым выкидывает все директивы с меньшим приоритетом

/**
     * Once the directives have been collected, their compile functions are executed. This method
     * is responsible for inlining directive templates as well as terminating the application
     * of the directives if the terminal directive has been reached.
     *
     * @param {Array} directives Array of collected directives to execute their compile function.
     *        this needs to be pre-sorted by priority order.
     * @param {Node} compileNode The raw DOM node to apply the compile functions to
     * @param {Object} templateAttrs The shared attribute function
     * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
     *                                                  scope argument is auto-generated to the new
     *                                                  child of the transcluded parent scope.
     * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
     *                              argument has the root jqLite array so that we can replace nodes
     *                              on it.
     * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
     *                                           compiling the transclusion.
     * @param {Array.<Function>} preLinkFns
     * @param {Array.<Function>} postLinkFns
     * @param {Object} previousCompileContext Context used for previous compilation of the current
     *                                        node
     * @returns linkFn
     */
function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, jqCollection, originalReplaceDirective, preLinkFns, postLinkFns, previousCompileContext) {
...
      var terminalPriority = -Number.MAX_VALUE,
...
      // executes all directives on the current element
      for(var i = 0, ii = directives.length; i < ii; i++) {
...
        if (terminalPriority > directive.priority) {
          break; // prevent further processing of directives
        }
...
        if (directive.terminal) {
          nodeLinkFn.terminal = true;
          terminalPriority = Math.max(terminalPriority, directive.priority);
        }
      }
...
}
Ответить с цитированием
  #7 (permalink)  
Старый 19.02.2014, 10:41
Профессор
Отправить личное сообщение для Shitbox2 Посмотреть профиль Найти все сообщения от Shitbox2
 
Регистрация: 04.10.2010
Сообщений: 571

Спасибо! Вкурил)
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Игра в демки, пиар ангуляра и обучение. DjDiablo Angular.js 39 07.06.2014 13:11
AngularJs isolated scope directive sealmu Angular.js 4 14.11.2013 12:09
проверка формы не работает в ie begelme Javascript под браузер 6 13.08.2013 01:00
Доступ к значениям элементов формы модального окна. =VNK= jQuery 5 14.01.2012 16:00
в модальном окне не работает скрипт проверки формы necroms jQuery 1 11.03.2011 15:14