Использование ng-модели для динамически создаваемого элемента

#javascript #angularjs

#javascript #angularjs

Вопрос:

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

Шаблон:

 <div child-ng-model="userReg.candidateData.PrimarySkills">
   <!-- this div creates an input element on runtime -->
</div>
 

Директива:

 (function (window) {
  'use strict';

    angular.module('myApp.userRegistration.directive')
    .directive('childNgModel', ['$compile', function ($compile) {
        return {
            restrict: 'A',
            scope: {
                childNgModel: '@'
            },
            link: function (scope, element, attrs) {
                var el = element.children().eq(0);
                el.attr('ng-model', scope.childNgModel);
                $compile(el)(scope);
            }
        }
    }]);
})(window);
 

Ниже вы можете увидеть, какое правильное значение присваивается ng-model:
привязка к ng-модели

Текст, который я ввожу в поле ввода, не фиксируется моей моделью (userReg.candidateData.PrimarySkills). Почему это происходит? Что я здесь делаю не так?

Ответ №1:

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

Попробуйте выполнить следующее:

 (function (window) {
  'use strict';

   angular.module('myApp.userRegistration.directive')
    .directive('childNgModel', ['$compile', function ($compile) {
        return {
            restrict: 'A',
            scope: true, // create a normal child scope
            link: function (scope, element, attrs) {
                var el = element.children().eq(0);
                el.attr('ng-model', attrs.childNgModel); // just get the attribute value
                $compile(el)(scope);
            }
        }
    }]);
})(window);
 

Комментарии:

1. Спасибо. Есть еще одна незначительная, не связанная с этим проблема 🙂 Когда я утешаю. зарегистрируйте мой объект candidateData, я не вижу всех свойств в окне инструмента Chrome dev. Некоторые свойства обрезаются символом «…» в конце. Даже после нажатия стрелки, которая расширяет объект, я не вижу всех свойств. Есть ли способ это исправить? Вот ссылка: s18.postimg.org/4bv9c1r7d/Untitled2.png

2. @dk49 Это делает директиву напрямую зависимой от контроллера и является плохой практикой. ( docs.angularjs.org/guide /… см. зеленую заметку над этим абзацем)

3. @gyc Зависимости нет. (Имя) модели передается директиве, поэтому директиву можно использовать с любым контроллером.

4. @gyc, zeroflagL прав. Имя «MyApp.UserRegistration.directive» — это, по сути, модуль, к которому я прикрепил свою директиву. Возможно, соглашение об именовании вас смутило. Мы в основном следуем очень модульному шаблону, в котором каждая директива / контроллер / сервер регистрируется в отдельном модуле. Чтобы определить иерархию, мы следуем соглашению об именовании ‘appModuleName.featureModuleName.directive / controller / service’. Этот шаблон позволяет многократно использовать директивы, контроллеры и службы по всему приложению в разных модулях.

5. Ваша директива имеет то же имя, что и переменная области видимости внутри директивы «childNgModel». Это плохая практика. Вы и zeroflagL можете следовать или не следовать хорошей практике. Это больше не мое дело. Спасибо. (у вас есть все необходимые ссылки и правильный ответ (zeroflagL или мои правильные))

Ответ №2:

Модель недоступна внутри директивы.

Сначала необходимо установить двустороннюю привязку:

 scope: {
  childNgModel: '='
 

Изменение модели ввода на childNgModel :

 el.attr('ng-model', "childNgModel");
$compile(el)(scope);
 

Теперь входные данные обновляются childNgModel внутри директивы, которая сама связана с userReg.candidateData.PrimarySkills внешней директивой.

Ответ №3:

Вы передаете модель в виде интерполированной строки, используя ‘@’.

Вместо этого попробуйте использовать ‘=’.

Если вы хотите, чтобы интерполированная строка содержалась в модели, вам нужно окружить ее {{ child-ng-model="userReg.candidateData.PrimarySkills" }}

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

 function MyController() {
  this.userReg = {candidateData: {PrimarySkills:["123", "456", "789"]}};
}
function childNgModel($compile) {
  return {
    restrict: 'A',
    scope: {
      value: '='
    },
    link: function (scope, element, attrs) {
      console.log(scope.value);
    }
  }
}

angular.module('app', []);
angular.module('app')
  .controller('MyController', MyController)
  .directive('childNgModel', childNgModel); 
 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app="app">
  <div ng-controller="MyController as ctrl">
    <div child-ng-model value="ctrl.userReg.candidateData.PrimarySkills">
    </div>
  </div>
</div> 

ИЛИ это

 function MyController() {
  this.userReg = {candidateData: {PrimarySkills:["123", "456", "789"]}};
}
function childNgModel($compile) {
  return {
    restrict: 'A',
    scope: {
      value: '@'
    },
    link: function (scope, element, attrs) {
      console.log(scope.value);
    }
  }
}

angular.module('app', []);
angular.module('app')
  .controller('MyController', MyController)
  .directive('childNgModel', childNgModel); 
 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<div ng-app="app">
  <div ng-controller="MyController as ctrl">
    <div child-ng-model value="{{ctrl.userReg.candidateData.PrimarySkills}}">
    </div>
  </div>
</div> 

Комментарии:

1. «использование одного и того же имени для директивы и модели в директиве является плохой практикой» , так что, по вашему мнению ng-model="foo" , должно быть ng-model value="foo" . Почему именно?

2. Нет, ваша директива не должна иметь то же имя, что и атрибут, который вы привязываете к области видимости. Это сбивает с толку. Вы можете вызвать директиву «myDirective» и модель ng-model.

3. Директива вызывается ngModel , и мы не можем ее переименовать, потому что она встроенная. И вы говорите, что это плохой дизайн и сбивает с толку, но ни у кого никогда не было проблем с этим. Вы все еще не объяснили причину своего мнения.

4. @zeroflagL О чем ты говоришь? Вы, кажется, очень смущены. childNgModel — это ЕГО директива и переменная области видимости, привязанная к ней одновременно. Это плохая практика. ng-model — это угловая директива, конечно, вы не можете ее изменить. Где вы видите ссылку на ng-model здесь??

5. Вы написали: «использование одного и того же имени для директивы и модели в директиве является плохой практикой» . ngModel делает именно это. Так что, по вашему мнению, ngModel плохо спроектировано. И вы все еще не объяснили, почему это плохая практика.