Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check $pristine status of ngModel without using a form

Am trying to figure out how to check the state of a ngModel without using a form tag. I don't have wrappers is just basic input element with a ngModel.

All the examples I have found so far are for form validations and in this case, there is no form.

When i tried something like:

HTML

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

SCRIPT:

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

I get undefined.

Is there a way to check the state of the ngModel without adding a watch directive to it? it seems it would be something basic that is part of the framework. Why wouldn't this work?

like image 222
J Castillo Avatar asked Mar 03 '14 16:03

J Castillo


People also ask

What does [( ngModel )] do?

The ngModel directive is a directive that is used to bind the values of the HTML controls (input, select, and textarea) or any custom form controls, and stores the required user value in a variable and we can use that variable whenever we require that value. It also is used during form validations.


2 Answers

There are two ways:

1. Use ng-form:

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

Now you can access the model either at $scope.myForm.namein your controller or with myForm.name in your view:

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

2. Use angular.element().controller('ngModel') (Don't do this one, bad bad bad)

Alternatively, you could hack your way around it. But this is going to be ugly, untestable, and gross:

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

Edit: Your situation (per your comment) inside of a repeater

the only difference between my example and your is that the input field is inside a ng-repeater. Thought that wouldn't matter but I guess it does.

And now it's time to ask yourself what you're doing and why... You can still get the information you need using ng-form, but you'll need to do some crazy stuff I wouldn't recommend:

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

.. commence craziness:

// 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;
}

It's probably time to rethink your strategy

I'm not sure what your end goal is, but you might want to rethink how you're going about it and why. Why do you need programmatic access to $pristine in your controller? What alternatives are there? Etc.

I, for one, would try to leverage an ng-change event and update some flag on my item in my repeater, and leave the ng-form stuff for validation:

<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>
like image 134
Ben Lesh Avatar answered Sep 20 '22 13:09

Ben Lesh


If you give the <form> element a name attribute, then the <form> will be added to the $scope object as a property.
Field controller will then be attached to the form property.

As weird as it could seem, you have to define an enclosing form with a name attribute like so:

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

and call the property with:

$scope.myForm.lastname.$dirty

Indeed, ngModelController (field) is attached to ngFormController (form).

like image 27
Mik378 Avatar answered Sep 20 '22 13:09

Mik378