Проверьте $первозданный статус ngModel без использования формы

Я пытаюсь выяснить, как проверить состояние ngModel без использования тега формы. У меня нет обертки - это просто базовый элемент ввода с ngModel.

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

Когда я попробовал что-то вроде:

HTML

<input type="text" ng-model="lastname">

SCRIPT:

if($scope.lastname.$dirty) {
  console.log('last name has changed');
}

Я получаю undefined.

Есть ли способ проверить состояние ngModel без добавления в него директивы watch? кажется, что это будет что-то основное, что является частью структуры. Почему это не работает?

Ответ 1

Существует два способа:

1. Используйте ng-form:

<span ng-form="myForm">
  <input type="text" name="name" ng-model="name" required/>
</span>

Теперь вы можете получить доступ к модели либо в $scope.myForm.name в вашем контроллере, либо с помощью myForm.name в вашем представлении:

var isPristine = $scope.myForm.name.$pristine;

2. Используйте angular.element().controller('ngModel') (не делайте этого, плохо плохо плохо)

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

var elem = angular.element(document.getElementById('myElement'));
var model = elem.controller('ngModel');
var isPristine = model.$pristine;

Изменить: ваша ситуация (за ваш комментарий) внутри репитера

Единственное различие между моим примером и вашим состоит в том, что поле ввода находится внутри ng-повторителя. Думал, что это не имеет значения, но я предполагаю, что это так.

И теперь настало время спросить себя, что вы делаете, и почему... Вы все еще можете получить необходимую информацию, используя ng-form, но вам нужно будет сделать некоторые сумасшедшие вещи, которые я бы не сделал рекомендуем:

<div ng-repeater="item in items track by $index">
  <span ng-form="rptrForm">
    <input type="text" name="name" ng-model="item.name" required/>
  </span>
</div>

.. начать сумасшествие:

// get the first child scope (from the repeater)
var child = $scope.$$childHead;
while(child) {
  var isPristine = child.rptrForm.$pristine;
  var item = child.item;
  if(!isPristine) {
    // do something with item
  }
  child = child.$$nextSibling;
}

Вероятно, время переосмыслить вашу стратегию

Я не уверен, какова ваша конечная цель, но вы, возможно, захотите переосмыслить, как вы собираетесь и почему. Зачем вам нужен программный доступ к $первозданному в вашем контроллере? Какие существуют альтернативы? Etc.

Я, например, попытаюсь использовать событие ng-change и обновить некоторый флаг в моем элементе в своем повторителе и оставить материал ng-form для проверки:

<div ng-repeat="item in items track by $index" ng-form="rptrForm">
   <input type="text" name="name" ng-model="item.name" ng-change="item.nameChanged = true" required/>
   <span ng-show="rptrForm.name.$error.required>Required</span>
</div>

Ответ 2

Если вы укажете атрибут <form> a name, тогда <form> будет добавлен в объект $scope как свойство.
Контроллер поля будет прикреплен к свойству form.

Как ни странно, вам нужно определить form с атрибутом name:

<form name="myForm">
  <input type="text" name="lastName" ng-model="lastname">
</form>

и вызовите свойство с помощью:

$scope.myForm.lastname.$dirty

Действительно, ngModelController (поле) присоединено к ngFormController (форме).

Ответ 3

Я использовал ответ Ben Lesh для решения той же проблемы. Я показывал список уведомлений, и моя цель состояла в том, чтобы поразить мой api с измененными моделями. Не только изменено, либо; изменено значение.

Я начинаю с инициализации некоторого частного состояния на моем контроллере:

// Private state
var originalModels = {};
var changedModels = [];

Затем я сохраняю копии исходных моделей, извлеченных из API:

// Create a hash of copies of our incoming data, keyed by the unique Code
for (var i = 0; i <= data.length - 1; i++) {
    var np = data[i];
    originalModels[np.Code] = angular.copy(np);
}

Затем мы хотим убедиться, что при изменении модели мы добавим ее в коллекцию измененных моделей (или удалим ее из коллекции, если никаких реальных изменений не произошло):

function modelChanged(m) {
    var originalModel = originalModels[m.Code];
    var hasChanged = !angular.equals(originalModel, m);

    // If the model has changed and is not present in our collection of changed models, add it
    if (hasChanged && changedModels.indexOf(m) === -1) {
        changedModels.push(m);
    }

    // If the model has not changed and is present in our collection of changed models, remove it
    if (!hasChanged && changedModels.indexOf(m) > -1) {
        var i = changedModels.indexOf(m);
        changedModels.splice(i, 1);
    }
}

Наконец, мы связываем их вместе в нашем ng-repeat:

<tr ng-repeat="np in npc.notificationPreferences">
    <td>{{np.DisplayName}}</td>
    <td>
        <input type="checkbox"
               ng-model="np.Sms"
               ng-checked="np.Sms"
               ng-disabled="!np.SmsEnabled"
               ng-change="npc.modelChanged(np)"/>
    </td>
</tr>

Теперь вместо того, чтобы отбрасывать каждую строку в мой API, я просто нажимаю измененные модели. Это также имеет преимущество в том, что вы можете ng-отключить кнопку отправки, если ничего не изменилось (т.е. Коллекция changedModels пуста).