I'm trying to $watch the $error or the $valid value of a control. This is the control:
<form id="myForm" name="myForm">
<input name="myInput" ng-model="myInputMdl" business-validation/>
</form>
business-validation is a custom directive that alters the validity of the control. I've attempted the following approaches (using either $valid or $error) based on what I've read at AngularJS directive watch validity:
This does not work since $valid does not exist on myForm.myInput.
$scope.$watch('myForm.myInput.$valid', function (isValid) {
$scope.usefulVariable = step3.CreditCardNumber.$valid;
},true);
This does not work since validity.valid apparently cannot be watched.
$scope.$watch('myForm.myInput.validity.valid', function (isValid) {
$scope.usefulVariable = step3.CreditCardNumber.$valid;
},true);
This does not work since $scope.myInputMdl is not watched on every change.
$scope.$watch('$scope.myInputMdl', function (isValid) {
$scope.usefulVariable = step3.CreditCardNumber.$valid;
},true);
Can't the validity be watched from a controller?
EDIT
I'm not trying to write or edit business-validation directive. What I'm trying is to $watch $valid or $error from form's controller.
EDIT 2
Controller's code is:
app.controller('WizardBusinessActionCtrl',
function ($scope, $http, $parse, $filter, wizardBusinessActionService, $timeout) {
//controller code
}
);
I don't see any reason why your first variant shouldn't work.
HTML:
<div ng-app="myApp">
<div data-ng-controller="MainController">
<form name="myForm">
<input name="myInput" ng-model="myInputMdl" business-validation />
</form>
</div>
</div>
Controller and directive:
var myApp = angular.module('myApp', []);
myApp.controller('MainController', function ($scope) {
$scope.$watch('myForm.myInput.$valid', function (validity) {
console.log('valid', validity);
});
});
myApp.directive('businessValidation', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, elem, attr, ctrl) {
function validate (input) {
return input === 'hello';
}
ctrl.$parsers.unshift(function (value) {
var valid = validate(value);
ctrl.$setValidity('businessValidation', valid);
return valid ? value : undefined;
});
ctrl.$formatters.unshift(function (value) {
ctrl.$setValidity('businessValidation', validate(value));
return value;
});
}
};
});
$valid property value will change when myInput validity changes, and $watch callback will be fired.
See example: http://jsfiddle.net/Lzgts/287/
Try the code below. Working Plunker
HTML
<div ng-controller="ExampleController">
<form name="userForm" novalidate >
Name:
<input type="text" name="userName" ng-model="firstName" required />
</form>
<div>{{firstName}}</div>
<input type = 'button' value = 'Submit' ng-click ='validateInput()'/>
</div>
JavaScript
angular.module('getterSetterExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.validateInput = function(){
$scope.$watch($scope.userForm.userName.$valid, function() {
if($scope.userForm.userName.$valid){
alert('Value is True');
}
else{
alert('Value is False');
}
});
}
}]);
Related
I'm trying to implement an asynchronous validation by using a custom directive.
This is the directive
moduloArea.directive('uniqueName', function($http, $q) {
return {
require : 'ngModel',
link: function($scope, element, attrs, ngModel) {
ngModel.$asyncValidators.nombre = function(modelValue, viewValue) {
return $http.get('/checkUsernameAvailability/'+viewValue).then(
function(response) {
if (!response.data.validUsername) {
return $q.reject(response.data.errorMessage);
}
return true;
}
);
};
}
};
});
The result in console
As you can see when the root username is typed the return is an JSON object because this username is already taken.
But in the HTML the form in $invalid when the directive unique-name is inserted.
<form name="registerUsernameForm" novalidate="novalidate">
<input type="text" name="username" data-ng-model="person.userName" data-unique-name="" required="required"/>
<span data-ng-show="registerUsernameForm.username.$error.uniqueName">This username is already taken.</span>
<button type="submit" data-ng-disabled="registerUsernameForm.$invalid || registerUsernameForm.$pending" data-ng-click="registerPerson(person)"> Save Person </button>
</form>
I'm using the data-unique-name="" (="") because if I don't then thymeleaf generate the following error:
Attribute name "data-unique-name" associated with an element type
"input" must be followed by the ' = ' character.
What do you think can be wrong?
You are validating nombre not uniqueName. For this reason, uniqueName is still stay invalid.
moduloArea.directive('uniqueName', function($http, $q) {
return {
require : 'ngModel',
link: function($scope, element, attrs, ngModel) {
ngModel.$asyncValidators.uniqueName= function(modelValue, viewValue) {
var value = modelValue || viewValue;
return $http.get('/checkUsernameAvailability/'+value ).then(
function resolved(response) {
if (response.data && !response.data.validUsername) {
return $q.reject(response.data.errorMessage);
}
return true;
}, function rejected() {
//username does not exist, therefore this validation passes
return true;
}
);
};
}
};
});
I have a directive that validates all the fields of a form that contain the "validate" directive. In all fields the word "logan" must exist to be correct. At any given time I want and need, when I click on the "Re_Evaluate all the form" button, validate if the form is correct, iterating in all the elements of the form, just like when the $timeout function is executed the first time .
app.directive('validate', function ($timeout,$compile) {
return {
restrict: 'AE',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
if (!ngModel){
return;
}
$timeout(function() {
console.log(ngModel.$viewValue); //I need this, iterate in all elements with the directive 'validate', when re_evaluate() is clicked
if(ngModel.$viewValue=='logan'){
ngModel.$setValidity('validate',true);
}
else{
ngModel.$setValidity('validate',false);
}
})
scope.re_evaluate = function(){
console.log('I need re-evaluate all the form!')
}
}
};
});
http://jsfiddle.net/hmk0yg42/
The HTML is
<section ng-app="app">
<article ng-controller="appCtrl" class="container">
<form class="form-horizontal well" name="zform" invalidate>
<input type="text" name="mytext1" ng-model="my_text" validate />
<input type="text" name="mytext2" ng-model="my_text2" validate />
<input type="text" name="mytext3" ng-model="my_text3" validate />
<button class="btn btn-lg btn-primary btn-block" type="submit" ng-disabled="zform.$invalid">
Validate</button>
</form>
</article>
</section>
And the JS is
var app = angular.module('app', []);
app.controller('appCtrl', function ($scope) {
$scope.my_text='logan';
$scope.my_text2 = 'logan';
$scope.my_text3 = 'logan';
});
app.directive('validate', function () {
return {
restrict: 'AE',
require: 'ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
ngModelCtrl.$parsers.unshift(function(value) {
var valid = value == 'logan';
ngModelCtrl.$setValidity('logan',valid);
return value;
});
ngModelCtrl.$formatters.unshift(function(value) {
var valid = value == 'logan';
ngModelCtrl.$setValidity('logan', valid);
return value;
});
}
};
});
you don't need a re-evaluate button
I was following this SO Post on creating an Enter keypress directive.
Here is my JS, in which I simulate the same functionality:
JavaScript
var app = angular.module('myApp', []);
app.controller('MainCtrl', ['$scope', function($scope) {
$scope.greeting = 'Hola!';
}]);
app.directive('myEnter', function () {
return function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
if(event.which === 13) {
scope.$apply(function (){
scope.$eval(attrs.myEnter);
});
event.preventDefault();
}
});
};
});
function callServerWithSong(){
alert("calling!");
}
HTML
<div id="search" ng-app="myApp" ng-controller="MainCtrl">
<input type="text" id="search" my-enter="calServerWithSong()">
</div>
The problem is that when I select the input box, type a string and press enter, it doesn't report an error or execute the alert() which tells me that my directive must not be properly set up to fire when I keypress that element.
You had a typo of method name while passing through a directive attribute. Also the method should be there in $scope of controller.
HTML
<div id="search" ng-app="myApp" ng-controller="MainCtrl">
<input type="text" id="search" my-enter="callServerWithSong()">
</div>
Code
function callServerWithSong(){
alert("calling!");
}
$scope.callServerWithSong = callServerWithSong;
I am creating a form in AngularJS and I want validate the fields, the problem is that the required message appear only if write something in the input and after I delete it, but I want that the message appear after to focus the input
my code is the following
<input type="text" name="textInput" data-ng-model="field.data" class="form-control" required/>
<span ng-show="form.textInput.$dirty && form.textInput.$error.required">Required!</span>
Try the following
<span ng-show="form.textInput.$touched && form.textInput.$error.required">Required!</span>
This will show the message after you touched and left(lost focus) with the field invalid. Documentation
Yes, it's doable. First add a directive like this:
myApp.directive('trackFocus', ['$timeout', function($timeout) {
return {
restrict: 'A',
require: 'ngModel',
scope: true,
link: function ($scope, element, attr, ctrl) {
element.on("focus", function() {
$timeout(function() {
ctrl.hasFocus = true;
});
});
element.on("blur", function() {
$timeout(function() {
ctrl.hasFocus = false;
});
});
}
}
}]);
Then use the directive and modify your code:
<input type="text" name="textInput" ng-model="field.data" class="form-control" required track-focus />
<span ng-show="form.textInput.hasFocus && form.textInput.$dirty && form.textInput.$error.required">Required!</span>
I have written a custom directive to ensure that a text box can take only integer values.
But After using the directive, my $error.required flag always stay false irrespective of whether I have a value in the text field or not.
It works fine if I use the native input type,
<input name="name" ng-model="testvalue.number" required />
but when I use the custom directive,
<number-only-input input-value="testvalue.number" input-name="name"/>
shippingForm.name.$error.required is always false and it doesn't show the error "Please enter a value" even if the field is empty
This is the code
<body ng-controller="ExampleController">
<form name="shippingForm" novalidate>
<!--<input name="name" ng-model="testvalue.number" required />-->
<number-only-input input-value="testvalue.number" input-name="name"/>
<span class="error" ng-show="shippingForm.name.$error.required">
Please enter a value
</span>
</form>
</body>
<script>
angular.module('TextboxExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.testvalue = {number: 1, validity: true}
}])
.directive('numberOnlyInput', function () {
return {
restrict: 'EA',
template: '<input name="{{inputName}}" ng-model="inputValue" required />',
scope: {
inputValue: '=',
inputName: '='
},
link: function (scope) {
scope.$watch('inputValue', function(newValue,oldValue) {
if (newValue == undefined || newValue == null || newValue == "") {
return;
}
if (isNaN(newValue))
{
scope.inputValue = oldValue;
return;
}
});
}
};
});
</script>
Please guide
Sunil
You code has some flaws, but i think this is because you made the example incorrect, the main issue may be here:
inputName: '=' should be replaced with inputName: '#' to hold the string value of the input name
I'm not quite sure what's wrong with your example, it just doesn't work... Anyway here's a workaround which you can use to implement your functionality.
HTML:
<div ng-app="TextboxExample" ng-controller="ExampleController">
<form name="shippingForm" novalidate>
<input number-only-input type="text" name="name" ng-model="testvalue.number" required />
<!-- <number-only-input input-value="testvalue.number" input-name="name"/> -->
<span class="error" ng-show="shippingForm.name.$error.required">
Please enter a value
</span>
</form>
</div>
Controller:
angular.module('TextboxExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.testvalue = {number: 1, validity: true};
}])
.directive('numberOnlyInput', function () {
return {
link: function (scope, element, attrs) {
var watchMe = attrs["ngModel"];
scope.$watch(watchMe, function(newValue,oldValue) {
if(newValue == undefined || newValue == null || newValue == ""){
return;
} else if (isNaN(newValue)) {
var myVal = watchMe.split(".");
switch (myVal.length) {
case 1:
scope[myVal[0]] = oldValue;
break;
case 2:
scope[myVal[0]][myVal[1]] = oldValue;
}
}
});
}
};
});