How can I add a class to an input if the input is changed with AngularJS?
Solution 1
There are two good ways to approach this problem:
1. Use the built-in ng-dirty
class that Angular puts on the element.
When you change an input managed by Angular, it adds some CSS classes to the input for various states. These include:
-
ng-pristine
- the input has not been modified -
ng-dirty
- the input has been modified
So, if you can modify your CSS to be based off the .ng-dirty
class, you're good to go.
2. Use a form
directive with the $dirty
flag.
When you use a form
element, Angular assigns a FormController
instance on the scope with the same name as the name
attribute on the form; each input inside the form gets attached to that FormController instance as a property, again with the same name as the name
attribute on the input. For example,
<form name="myForm">
<input type="text" name="myInput">
</form>
gives you
$scope.myForm.myInput
Each input property has some of its own properties on it, including $pristine
and $dirty
; these work just like the CSS classes listed above. Thus, you can check for the $dirty
flag on the input and use ng-class
to conditionally apply a class to the element. An example:
<div ng-controller="MainController">
<form name="myForm">
<input name="myInput" ng-model="model" ng-maxlength="3"
ng-class="{changed: myForm.myInput.$dirty}">
</form>
</div>
You can find a working example here: http://jsfiddle.net/BinaryMuse/BDB5b/
Solution 2
Take a look at this jsfiddle: http://jsfiddle.net/hNrEV/2/
The main idea is using $scope.$watch
to watch for changes to the input box. I gave it an id of rowTitle
, and used a directive called watchRowTitle
that watches for changes to $scope.row.title
, and adds a class 'red' that colors the text red whenever the text in the input box is equal to 'wrong title'.
It is probably good practice to do DOM manipulation in directives. Here, the watchRowTitle
directive returns an object with 4 keys:
-
template - the html that replaces the
watch-row-title
tag. we dont need this here -
scope - Here we make use of an isolated scope. Basically, the '=' establishes a 2-way data binding between between
scope.title
inside thewatch-row-title
directive and the$scope.row.title
value inside theMyCtrl
controller. -
restrict - We give it a value of
E
, which stands for element. So this restricts the use of thewatch-row-title
directive within html tags, in other words:<watch-row-title></watch-row-title>
-
link - this is the link function, where the interesting stuff happens. In here, we use
scope.$watch
ontitle
. We have to supply a function with 2 parametersnewValue
andoldValue
(you can name them to something else, but naming them this way is more meaningful), that holds the new and old values of the variable being watched. Whenever thescope.title
variable becomes the string 'wrong title', it adds the CSS class 'red' to the input box with idrowTitle
(notice how the text in the input box turns red). Otherwise, it removes that CSS class. This portion is done using JQuery.
HTML:
<div ng-app="myApp" ng-controller="MyCtrl">
<input id="rowTitle" type="text" ng-model="row.title" class="ng-pristine ng-valid" />
<watch-row-title title="row.title"></watch-row-title>
</div>
CSS:
.red {
color: red;
}
JavaScript:
angular.module('myApp', [])
.controller('MyCtrl', [
'$scope',
function ($scope) {
$scope.row = {};
}
])
.directive('watchRowTitle', [
function () {
return {
template: '',
scope: {
title: '='
},
restrict: 'E',
link: function(scope, element, attr) {
scope.$watch('title', function(newValue, oldValue) {
if (newValue === 'wrong title') {
$('#rowTitle').addClass('red');
} else {
$('#rowTitle').removeClass('red');
}
});
}
};
}
]);
Related videos on Youtube
Admin
Updated on September 15, 2022Comments
-
Admin over 1 year
I coded the following in my form:
<td><input type="text" ng-model="row.title" /></td>
When I look at my DOM with Chrome developer tools I see the following:
<input type="text" ng-model="row.title" class="ng-pristine ng-valid">
How can I make it so that when there is a change made to the input that the input has a class added to it?
-
Ivan Chernykh almost 11 yearsand what if you haven't jQuery?
-
EpokK almost 11 yearsYou must have lite jQuery or Zepto with AngularJS ;)
-
Ivan Chernykh almost 11 yearsabsolutely no , but what you have is jqLite. so the question actually is how to do what you did with jqLite ?
-
EpokK almost 11 years"Does Angular use the jQuery library? Yes, Angular can use jQuery if it's present in your app when the application is being bootstrapped. If jQuery is not present in your script path, Angular falls back to its own implementation of the subset of jQuery that we call jQLite."
-
Ivan Chernykh almost 11 yearsexactly. so i'm asking how can you do it with jqLite ?
-
Michelle Tilley almost 11 yearsFrom the AngularJS FAQ "Common Pitfalls": "Stop trying to use jQuery to modify the DOM in controllers. Really. That includes adding elements, removing elements, retrieving their contents, showing and hiding them. Use built-in directives, or write your own where necessary, to do your DOM manipulation."
-
Irshu about 8 yearsIt's an anti-pattern to manipulate dom inside the controller.