AngularJS: How to refresh $viewValue even when $modelValue is unchanged - angularjs

In the example below, the value in input 'ia' can get out of sync with the model value (e.g. if you type in 'aaa'). What I would like to achieve is when the input 'ia' loses focus, update its value to the formatted value of the current model value (e.g. when model value is null, update the view value to string 'N/A'). Anybody know I this might be achieved? Thanks.
The current behaviour is if you type in 'aaa' as profession, model value is updated to null bot 'aaa' stays in the input.
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html ng-app="myapp">
<head>
<script>
var myapp = angular.module('myapp', []);
myapp.controller('mycontroller', function($scope) {
$scope.model = {
name: "ttt",
age: 24,
profession: null
};
});
var professionList = [{
id: 1,
name: "p1"
}, {
id: 2,
name: "p2"
}, {
id: 3,
name: "p3"
}, {
id: 4,
name: "p4"
}];
myapp.directive("prof", function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
ngModel.$formatters.push(function(value) {
for (var i = 0; i < professionList.length; i++) {
if (value == professionList[i].id)
return professionList[i].name;
}
return "N/A";
});
//format text from the user (view to model)
ngModel.$parsers.push(function(value) {
for (var i = 0; i < professionList.length; i++) {
if (value == professionList[i].name)
return professionList[i].id;
}
return null;
});
element[0].ngModel = ngModel;
}
};
});
</script>
</head>
<body ng-controller="mycontroller">
<form>
Name:
<input ng-model="model.name" />
<br />Age:
<input ng-model="model.age" />
<br />Profession:
<input prof="" ng-model="model.profession" id="ia" />
<input ng-model="model.profession" />
</form>
<hr />Name: {{model.name}}
<br />Age: {{model.age}}
<br />Profession: {{model.profession}}
</body>
</html>
UPDATE:
I found a solution based on the answer in this question
//add this to the link function:
ngModel.$render = function(){
element[0].value = ngModel.$viewValue;
};
element[0].onblur = function(){
var viewValue = ngModel.$modelValue;
for (var i in ngModel.$formatters) {
viewValue = ngModel.$formatters[i](viewValue);
}
ngModel.$viewValue = viewValue;
ngModel.$render();
};

While returning null you are not re-initializing ngModel and I dont think directive is needed here , there is something called ng-blur in angularjs,
Profession : <input ng-model="model.profession" ng-blur="checkProfession() "/>
Profession ID : <input ng-model="model.id" />
In your controller write a function as,
$scope.checkProfession=function(){
var flag=0;
for (var i = 0; i < professionList.length; i++) {
if ($scope.model.profession == professionList[i].name){
$scope.model.id=professionList[i].id;
flag=1;
}
if(!flag){
$scope.model.id="";
$scope.model.profession="";
}
}
}

Related

Enabling checkbox when ng-checked value is False?

I have created an checkbox as
<input type="checkbox" name="enableSchedule" ng-model="pr.closed" ng-checked="pr.closed">
Now the condition for "ng-checked="pr.closed" by default evaluates to false as the value of pr.closed is false. but what I want to do is enable the checkbox when the value of pr.closed is false and disbaled when the value is true.
also the ng-model should be updated accordingly i.e if my checkbox is enabled the value of ng-model should be true else false.
You can just negate the ng-checked with negation operator !. But since it is advised not to use ng-model with ng-checked, you can use ng-true-value="false" ng-false-value="true" to trigger the values of your checkbox based on the value of ng-model
<input type="checkbox" name="enableSchedule" ng-model="pr.closed"
ng-true-value="false" ng-false-value="true">
angular.module("App",[])
.controller("ctrl",function($scope){
$scope.pr = {closed:false };
});
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body ng-app="App" ng-controller="ctrl">
<p>My checkbox:</p>
<input type="checkbox" name="enableSchedule" ng-model="pr.closed"
ng-true-value="false" ng-false-value="true">
Value of ng-model is {{pr.closed}}
</body>
</html>
change the checked="!pr.closed" to check on false.
angular.module("app",[])
.controller("ctrl",function($scope){
$scope.pr = {'closed':false,"modelval" : true }
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<input type="checkbox" name="enableSchedule" ng-model="pr.modelval" ng-checked="!pr.closed">checked value is {{pr.closed}} <br>
model value is {{pr.modelval}}
</div>
angular.module('checklist-model', [])
.directive('checklistModel', ['$parse', '$compile', function($parse, $compile) {
// contains
function contains(arr, item, comparator) {
if (angular.isArray(arr)) {
for (var i = arr.length; i--;) {
if (comparator(arr[i], item)) {
return true;
}
}
}
return false;
}
// add
function add(arr, item, comparator) {
arr = angular.isArray(arr) ? arr : [];
if(!contains(arr, item, comparator)) {
arr.push(item);
}
return arr;
}
// remove
function remove(arr, item, comparator) {
if (angular.isArray(arr)) {
for (var i = arr.length; i--;) {
if (comparator(arr[i], item)) {
arr.splice(i, 1);
break;
}
}
}
return arr;
}
// http://stackoverflow.com/a/19228302/1458162
function postLinkFn(scope, elem, attrs) {
// exclude recursion, but still keep the model
var checklistModel = attrs.checklistModel;
attrs.$set("checklistModel", null);
// compile with `ng-model` pointing to `checked`
$compile(elem)(scope);
attrs.$set("checklistModel", checklistModel);
// getter / setter for original model
var getter = $parse(checklistModel);
var setter = getter.assign;
var checklistChange = $parse(attrs.checklistChange);
var checklistBeforeChange = $parse(attrs.checklistBeforeChange);
// value added to list
var value = attrs.checklistValue ? $parse(attrs.checklistValue)(scope.$parent) : attrs.value;
var comparator = angular.equals;
if (attrs.hasOwnProperty('checklistComparator')){
if (attrs.checklistComparator[0] == '.') {
var comparatorExpression = attrs.checklistComparator.substring(1);
comparator = function (a, b) {
return a[comparatorExpression] === b[comparatorExpression];
};
} else {
comparator = $parse(attrs.checklistComparator)(scope.$parent);
}
}
// watch UI checked change
scope.$watch(attrs.ngModel, function(newValue, oldValue) {
if (newValue === oldValue) {
return;
}
if (checklistBeforeChange && (checklistBeforeChange(scope) === false)) {
scope[attrs.ngModel] = contains(getter(scope.$parent), value, comparator);
return;
}
setValueInChecklistModel(value, newValue);
if (checklistChange) {
checklistChange(scope);
}
});
function setValueInChecklistModel(value, checked) {
var current = getter(scope.$parent);
if (angular.isFunction(setter)) {
if (checked === true) {
setter(scope.$parent, add(current, value, comparator));
} else {
setter(scope.$parent, remove(current, value, comparator));
}
}
}
// declare one function to be used for both $watch functions
function setChecked(newArr, oldArr) {
if (checklistBeforeChange && (checklistBeforeChange(scope) === false)) {
setValueInChecklistModel(value, scope[attrs.ngModel]);
return;
}
scope[attrs.ngModel] = contains(newArr, value, comparator);
}
// watch original model change
// use the faster $watchCollection method if it's available
if (angular.isFunction(scope.$parent.$watchCollection)) {
scope.$parent.$watchCollection(checklistModel, setChecked);
} else {
scope.$parent.$watch(checklistModel, setChecked, true);
}
}
return {
restrict: 'A',
priority: 1000,
terminal: true,
scope: true,
compile: function(tElement, tAttrs) {
if ((tElement[0].tagName !== 'INPUT' || tAttrs.type !== 'checkbox') && (tElement[0].tagName !== 'MD-CHECKBOX') && (!tAttrs.btnCheckbox)) {
throw 'checklist-model should be applied to `input[type="checkbox"]` or `md-checkbox`.';
}
if (!tAttrs.checklistValue && !tAttrs.value) {
throw 'You should provide `value` or `checklist-value`.';
}
// by default ngModel is 'checked', so we set it if not specified
if (!tAttrs.ngModel) {
// local scope var storing individual checkbox model
tAttrs.$set("ngModel", "checked");
}
return postLinkFn;
}
};
}]);
var app = angular.module("app", ["checklist-model"]);
app.controller('Ctrl1', function($scope) {
$scope.roles = [
'guest',
'user',
'customer',
'admin'
];
$scope.user = {
roles: ['user']
};
$scope.checkAll = function() {
$scope.user.roles = angular.copy($scope.roles);
};
$scope.uncheckAll = function() {
$scope.user.roles = [];
};
$scope.checkFirst = function() {
$scope.user.roles.splice(0, $scope.user.roles.length);
$scope.user.roles.push('guest');
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="Ctrl1">
<label ng-repeat="role in roles">
<input type="checkbox" checklist-model="user.roles" checklist-value="role"> {{role}}
</label>
</div>

How to count the number of elements selected in a directive?

If you have a career-box directive like this:
<div ng-repeat='career in careers' career-box ng-click="toggleSelected()"> {{ career.name }} </div>
The directive:
app.directive('careerBox', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
scope.selected = false,
scope.toggleSelected = function() {
element.toggleClass('selected');
if(scope.selected) {
scope.selected = false;
} else {
scope.selected = true;
}
}
}
};
});
Every time a career-box is selected I would like to count the total number of career-boxes selected (selected=true) and enable a button if they are more than 0.
How can I do that in the code?
There is no need to write a custom directive. It can be done with Angular core directives:
vm.selectedCount = function(item) {
var count=0;
for (let i=0; i<vm.careers.length; i++) {
if (vm.careers[i].selected) count++;
}
return count;
}
<div ng-repeat='career in careers'
ng-click="career.selected = !career.selected"
ng-style="{'background-color': career.selected?'yellow':''}">
{{ career.name }}
</div>
<hr>Selected count: {{selectedCount()}}
The DEMO on PLNKR
The DEMO
angular.module("myApp",[]);
angular.module("myApp").controller("myVm", function($scope) {
var vm = $scope;
vm.careers = [ {name: "Police Officer", value: 1},
{name: "Nurse", value:2},
{name: "Doctor", value:3},
];
vm.selectedCount = function(item) {
var count=0;
for (let i=0; i<vm.careers.length; i++) {
if (vm.careers[i].selected) count++;
}
return count;
}
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="myApp" ng-controller="myVm">
<h1>Selected Div Example</h1>
<div ng-repeat='career in careers'
ng-click="career.selected = !career.selected"
ng-style="{'background-color': career.selected?'yellow':''}">
{{ career.name }}
</div>
<hr>Selected count: {{selectedCount()}}
</body>
First, you need to have a select element with the multiple property:
<select name="carers" multiple id="multipleCarers" ng-model="data.multipleCarers">
<option ng-repeat="career in careers" value="{{career.value}}">
{{career.name}}
</option>
</select>
After of that, you can get the count of options selected:
{{data.multipleCarers.length}}

Dynamically update ion.rangeSlider ngModel in AngularJS directive

I'm trying to update the value of an Ion.RangeSlider when its bound ng-model scope variable changes. The model updates when the Ion.RangeSlider is used, but not vice-versa. Other inputs with the same ng-model update when the model value changes, so this must be some special case.
Edit: Woo! Here's a snippet #lin :) Also jsfiddle.
var app = angular.module('ngModelIonRangeSliderDemo', []);
app.controller('MainCtrl', function ($scope, $rootScope, $timeout) {
$scope.someNumber = 10;
}).directive('ionRangeSlider', function ionRangeSlider() {
return {
restrict: 'A',
scope: {
rangeOptions: '=',
model: '=ngModel'
},
link: function (scope, elem, attrs) {
scope.$watch('model',function () {
elem.ionRangeSlider(scope.rangeOptions);
});
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.10/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/1.1.2/ui-bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.6/js/ion.rangeSlider.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.6/css/ion.rangeSlider.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.6/css/ion.rangeSlider.skinFlat.min.css" />
<div ng-app="ngModelIonRangeSliderDemo">
<div ng-controller="MainCtrl" class="wrapper">
<h3>Text input updates slider, but not vice-versa.</h3>
<input ion-range-slider ng-model="someNumber" range-options="{min: -100, max: 100, step: .001}">
<br/>
<input type="text" ng-model="someNumber" class="form-control">
</div>
</div>
I have tried all kinds of suggestions in over ten somewhat-related stack overflow posts (which is how I have set up the current scope.$watch scheme on the ngModel), but none have worked. There aren't any errors in my console. What's wrong? Also, why doesn't it work without any mention of the model in my directive? Please let me know if there's anything important I have failed to include in this post.
Just use slider.update() inside your directive and you will be fine:
var app = angular.module('myApp', []);
app.controller('MainCtrl', function ($scope, $rootScope, $timeout) {
$scope.someNumber = 15;
$scope.apply = false;
}).directive('ionRangeSlider', function ionRangeSlider() {
return {
restrict: 'A',
scope: {
rangeOptions: '=',
model: '=ngModel',
apply: '=apply'
},
link: function (scope, elem, attrs) {
elem.ionRangeSlider(scope.rangeOptions);
scope.$watch('apply',function () {
if (scope.apply) {
scope.apply = false;
var slider = elem.data("ionRangeSlider");
slider.update({
from: scope.model
});
}
});
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.10/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/1.1.2/ui-bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.6/js/ion.rangeSlider.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.6/css/ion.rangeSlider.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/ion-rangeslider/2.1.6/css/ion.rangeSlider.skinFlat.min.css" />
<div ng-app="myApp" ng-controller="MainCtrl" class="wrapper">
<h3>Text input updates slider and vice-versa.</h3>
<input ion-range-slider ng-model="someNumber" apply="apply" range-options="{min: -100, max: 100, step: .001}">
<br/>
<input type="text" ng-model="someNumber" class="form-control" ng-change="apply = true">
</div>
Extra demo, how binding ion.rangeSlider to input works:
http://jsfiddle.net/IonDen/r5aox84v/
var $range = $(".js-range-slider"),
$inputFrom = $(".js-input-from"),
$inputTo = $(".js-input-to"),
instance,
min = 0,
max = 1000,
from = 0,
to = 0;
$range.ionRangeSlider({
type: "double",
min: min,
max: max,
from: 200,
to: 800,
onStart: updateInputs,
onChange: updateInputs
});
instance = $range.data("ionRangeSlider");
function updateInputs (data) {
from = data.from;
to = data.to;
$inputFrom.prop("value", from);
$inputTo.prop("value", to);
}
$inputFrom.on("input", function () {
var val = $(this).prop("value");
// validate
if (val < min) {
val = min;
} else if (val > to) {
val = to;
}
instance.update({
from: val
});
});
$inputTo.on("input", function () {
var val = $(this).prop("value");
// validate
if (val < from) {
val = from;
} else if (val > max) {
val = max;
}
instance.update({
to: val
});
});

Determine where this AngularJs Error $rootScope:infdig is coming from

Ok, I'm having a hard time trying to figure out what's causing this error. I think it may be due to a watch that I have in my routeOrderValidator directive but I can't see where I'm modifying the watch value. :(
Here is my Plunker and the error can be reproduced by entering a "3" into the Routing Order field for the John Smith reviewer.
Here is my directive code:
(function () {
'use strict';
angular
.module('app')
.directive('routeOrderValidator', routeOrderValidator);
routeOrderValidator.$inject = ['$filter'];
function routeOrderValidator($filter) {
var directive = {
require: 'ngModel',
link: link,
restrict: 'A'
};
return directive;
function link(scope, element, attrs, ngModel) {
scope.$watch(attrs.routeOrderValidator, function () {
ngModel.$validate();
}, true);
ngModel.$validators.routeOrder = function (modelValue, viewValue) {
return validate(scope, element, attrs, ngModel, modelValue, viewValue);
};
}
function validate(scope, element, attrs, ngModel, modelValue, viewValue) {
var isValid = true;
var reviewers = scope.$eval(attrs.routeOrderValidator);
if (!reviewers) {
return isValid;
}
var sorted = $filter('orderBy')(reviewers, 'route');
var i, len, count = 0;
for (i = 0, len = sorted.length; i < len; i++) {
if (sorted[i].office == 'Branch') {
count++;
}
}
for (i = 0, len = sorted.length; i < len; i++) {
if (count > 0) {
if (sorted[i].office == 'Branch') {
count--;
} else {
isValid = false;
break;
}
}
}
return isValid;
}
}
})();
Here is my controller code:
(function() {
'use strict';
angular
.module('app')
.controller('controller1', controller1);
controller1.$inject = ['$location'];
function controller1($location) {
var data = {
'title': 'More Snacks Please',
'description': 'Add beef jerky to the breakroom snacks.',
'reviewers': [{
'name': 'John Smith',
'office': 'Branch',
'route': '1'
}, {
'name': 'Amy Jones',
'office': 'Corporate',
'route': '2'
}, {
'name': 'Foo Bar',
'office': 'Corporate',
'route': '3'
}]
};
var vm = this;
vm.data = data;
}
})();
Here is my html:
<form name="form1">
<label>
Title:
<input type="text" name="title" ng-model="vm.data.title" />
</label>
<label>
Description:
<textarea type="text" name="description" ng-model="vm.data.description"></textarea>
</label>
<h3>Reviewers</h3>
<ul ng-repeat="reviewer in vm.data.reviewers">
<li>
<label>
Name:
<input type="text" name="name_{{$index}}" ng-model="reviewer.name" />
</label>
<label>
Office:
<select name="office_{{$index}}" ng-model="reviewer.office">
<option>Branch</option>
<option>Corporate</option>
</select>
</label>
<label>
Routing Order:
<input type="text"
name="route_{{$index}}"
ng-model="reviewer.route"
route-order-validator="vm.data.reviewers" />
</label>
<p ng-show="form1.route_{{$index}}.$error.routeOrder" class="error">Branch employees must be first in the routing order!</p>
</li>
</ul>
</form>
The issue that you have is that $validator will remove the incorrect object/attribute if it is invalid.
Example :
When Routing Order for John Smith is 3 then the route attribute will be removed as it is invalid.
This causing $watch to be triggered as the object is changed already and causing infinite loop.
One of the possible solution is to avoid ngModel.validate() until all other validation is completed (i.e validation of the individual routing order)
From :
scope.$watch(attrs.routeOrderValidator, function () {
ngModel.$validate();
}, true);
To:
scope.$watch(attrs.routeOrderValidator, function () {
if(ngModel.$valid )
{
ngModel.$validate();}
}, true);

ng-minlength in directive not populated when invalid

I'm creating an input directive that encapsulates a label, and some error messaging but I'm getting stuck with ng-minlength and ng-maxlength. The issue is that they don't populate the model value until it's a valid value, so my parent scope can display a value while my directive doesn't, and vice versa. View this plunk for an example of what I mean.
Is the only way around this to define my own minlength and maxlength validators? Is there some way configure this behaviour so the model is always populated? I want to use all the built in validators in my directive, so no doubt this will be an issue with all of them and I'd rather not redefine them all.
HTML:
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js#*" data-semver="1.3.0-beta.5" src="https://code.angularjs.org/1.3.0-beta.5/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="app" ng-controller="Controller">
<label>Outer scope 1</label>
<input name="input1" type="text" ng-model="model1" ng-minlength="4"/>
<br/>
<label>Directive scope 1</label>
<input-dir ng-model="model1" ng-minlength="0"></input-dir>
<br/>
<br/>
<br/>
<label>Outer scope 2</label>
<input name="input3" type="text" ng-model="model2"/>
<br/>
<label>Directive scope 2</label>
<input-dir ng-model="model2" ng-minlength="4"></input-dir>
</body>
</html>
Javascript:
var app = angular.module('app', []);
app.controller('Controller', function($scope){
$scope.model1 = "Model1";
$scope.model2 = "Model2";
});
app.directive('inputDir', function(){
return {
restrict: 'E',
template: '<input type="text" ng-model="model" ng-minlength="{{ minlength }}" />',
scope: {
model: '=ngModel',
minlength: '=ngMinlength'
}
};
});
For anyone else with the same issue, I solved this by redefining all the validators, except now they return the value when invalid so the model is populated. Just include the valuedValidators module. These validators are available on the $error object as vvminlength etc.
vv-validators.js
(function () {
'use strict';
var validators = {};
validators.vvUrl = function(value){
var urlRegex = new RegExp(/[-a-zA-Z0-9#:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9#:%_\+.~#?&//=]*)?/gi);
return urlRegex.test(value);
}
validators.vvEmail = function(value){
var emailRegex = new RegExp(/^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
return emailRegex.test(value);
}
validators.vvMinlength = function(value, min){
var huh = value.length >= parseInt(min);
return min && value && huh;
}
validators.vvMaxlength = function(value, max){
return max && value && value.length <= parseInt(max);
}
validators.vvMin = function (value, min) {
return min && parseFloat(value) >= parseFloat(min);
}
validators.vvMax = function (value, max) {
return max && parseFloat(value) <= parseFloat(max);
}
validators.vvPattern = function (value, pattern) {
return pattern && new RegExp(pattern).test(value);
}
validators.vvFloat = function (value) {
var floatRegex = new RegExp(/^\-?\d+((\.|\,)\d+)?$/);
return floatRegex.test(value);
}
validators.vvInteger = function (value) {
var integerRegex = new RegExp(/^\-?\d+$/);
return integerRegex.test(value);
}
var app = angular.module('valuedValidators', []);
var names = Object.keys(validators);
names.forEach(function(name){
app.directive(name, function(){
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, controller) {
controller.$parsers.unshift(function (viewValue) {
var valid = true;
var attrValue = attrs[name];
var func = validators[name];
if (attrValue !== 'false') {
valid = func(viewValue, attrValue);
controller.$setValidity(name.toLowerCase(), valid);
}
return viewValue;
});
}
};
});
});
}());
There is an even easier solution: use two textareas.
The first serves as a draft, the second is the model where the verification is to take place.
<textarea name="message_body_draft" cols="47" rows="15" style="width: 100%;"
ng-model="message_body_draft"
ng-change="message_body=message_body_draft"></textarea>
<textarea name="message_body" style="width: 100%;" disabled ng-model="message_body"
ng-minlength="100" required></textarea>
When the user writes in the first one, it automatically will populates the right model (the second one).

Resources