I have a directive that I put in the input of type class.
I add the blur, focus event to know when I entered and exit the input to make the effect of the label (Material Design), but when I wrap the value through the angular ng-model I need to know that the field was filled.
Any idea?
app.directive('formControl', function() {
return {
restrict: 'C',
link: function (scope, element, attrs) {
// Add class filled to form-control's that have a value
if(element.val()){
element.parent().addClass('filled');
}
// Any event here that can tell me that the value was changed by the angular so I can put the css class
element.bind('blur', function (e) {
input = angular.element(e.currentTarget);
if(input.val()){
input.parent().addClass('filled');
} else {
input.parent().removeClass('filled');
}
input.parent().removeClass('active');
}).bind('focus', function (e) {
input = angular.element(e.currentTarget);
input.parent().addClass('active');
});
}
};
});
Instead of adding the filled class inside the bind, you can add a watcher and add the class. Please refer the below example. Using colors in the classes to represent them getting added.
var app = angular.module('myApp', []);
app.controller('MyController', ['$scope', MyController]);
function MyController($scope) {
$scope.name = 'World';
$scope.name2 = 'hello';
}
app.directive('formControl', function() {
return {
restrict: 'C',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
// Add class filled to form-control's that have a value
if(ngModel.$viewValue){
element.parent().addClass('filled');
}
// Any event here that can tell me that the value was changed by the angular so I can put the css class
element.bind('blur', function (e) {
input = angular.element(e.currentTarget);
input.parent().removeClass('active');
}).bind('focus', function (e) {
input = angular.element(e.currentTarget);
input.parent().addClass('active');
});
scope.$watch(function(){return ngModel.$viewValue;}, function(newValue){
if('required' in attrs){
if(newValue){
element.parent().addClass('filled');
} else {
element.parent().removeClass('filled');
}
}
})
}
};
});
.filled{
background-color:lightblue;
}
.active{
border:1px solid red;
}
<div ng-controller='MyController' ng-app="myApp">
<label> The below input does not have required attribute</label>
<input type="text" class="form-control" ng-model="name">
<br>
<br>
<label> The below input has required attribute</label>
<input type="text" class="form-control" required ng-model="name2">
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.14/angular.min.js"></script>
Additionally if you want to show an error message like how you see in ng-messages.
var app = angular.module('myApp', []);
app.controller('MyController', ['$scope', MyController]);
function MyController($scope) {
$scope.name = 'World';
$scope.name2 = 'hello';
}
app.directive('formControl', function() {
return {
restrict: 'C',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
// Add class filled to form-control's that have a value
if(ngModel.$viewValue){
element.parent().addClass('filled');
}
// Any event here that can tell me that the value was changed by the angular so I can put the css class
element.bind('blur', function (e) {
input = angular.element(e.currentTarget);
input.parent().removeClass('active');
}).bind('focus', function (e) {
input = angular.element(e.currentTarget);
input.parent().addClass('active');
});
scope.$watch(function(){return ngModel.$viewValue;}, function(newValue){
if('required' in attrs){
if(newValue){
element.parent().addClass('filled');
} else {
element.parent().removeClass('filled');
}
}
})
}
};
});
.filled{
background-color:lightblue;
}
.active{
border:1px solid red;
}
div.filled > .error-message{
display:none;
}
div:not(.filled) > .error-message{
display:block;
}
.error-message{
text-align:center;
margin-top:5px;
}
<div ng-controller='MyController' ng-app="myApp">
<label> The below input does not have required attribute</label>
<input type="text" class="form-control" ng-model="name">
<br>
<br>
<label> The below input has required attribute</label>
<input type="text" class="form-control" required ng-model="name2">
<div class="error-message"> This Field is required</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.14/angular.min.js"></script>
I hope this solves your issue :)
Related
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 have created an angular directive for a repeatable section with form elements
I want the whole section/div to be highlighted when any of then input fields inside the div are in focus
template.html
<div class="col-md-12 employee-section">
<label for="name_{{$index}}">Name</label>
<input type="text" id="name_{{$index}}" class="col-md-6" ng-model="model.name"/>
<label for="address_{{$index}}">Address</label>
<input type="text" id="address_{{$index}}" class="col-md-6" ng-model="model.address"/>
</div>
directive
angular.module('test').directive('employee' , function(){
return {
link: function(scope, element){
},
restrict: 'AE',
scope: {
model: "="
},
templateUrl: 'template.html'
};
}
controller
angular.module('test').controller('employeeCtrl' , function($scope){
$scope.employees = [{name:'Jackk',address:'Main st'}, {name:'Jill',address:'Main st 123'}
});
html page
<div ng-repeat="employee in employees>
<employee model="employee"></employee>
</div>
Here's the directive which I was looking for with link for Plnkr
app.directive('ngFocusModel', function () {
return function (scope, element) {
var focusListener = function () {
scope.hasFocus = true;
scope.$digest();
};
var blurListener = function () {
scope.hasFocus = false;
scope.$digest();
};
element[0].addEventListener('focus', focusListener, true);
element[0].addEventListener('blur', blurListener, true);
};
});
I have this directive that prepends an <i> element before each <input> element with add-icon-element attribute. Now what i'm trying to do is to observe validation for each <input> element, so when the user types something in one of them the class of the <i> element that precedes will change to fa-check green-i. I tried to do it by using attrs.$observe to see when the class changes from ng-invalid to ng-valid but it fires only one time when the DOM is structured, it doesn't react to changes in the input element.
What am i doing wrong? is there a way to do it using the input $valid?
I saw some answers regarding one input with suggestions to add names to the form and input - but what can I do if I have multiple inputs that I need to validate and not just one?
angular.module('mean.theme')
.directive("addIconElement", function () {
return {
restrict: 'EA',
link: function (scope, inputElement, attrs) {
var $icon = $('<i class="fa"></i>');
inputElement.before($icon);
attrs.$observe('class', function(val){
if (val.indexOf("ng-valid") >= 0) {
inputElement.prev().addClass('fa-check green-i');
}
});
}
};
});
and this is one of my 'inputs' in the html:
<form role="form" name="createProjectForm" class="form-validation">
<div class="form-group">
<label class="control-label text-center center-block" for="project.name">
Name Your Project
</label>
<div class="input-icon right">
<input type="text" placeholder="type here" name="project.name"
ng-model="project.name" required="required" class="form-control" add-icon-element/>
</div>
</div>
<form>
You don't need create a directive for such case, you could achieve this by using ng-class directive, only change your field name from name="project.name" to name="project_name"
<div class="input-icon right">
<input type="text" placeholder="type here" name="project.name"
ng-class="{'fa-check green-i': createProjectForm.project_name.$valid}"
ng-model="project.name" required="required"
class="form-control"/>
</div>
Update
To make it generic way, you need to require ngModel directive on that element, which will give you access to the ngModelController.
angular.module('mean.theme')
.directive("addIconElement", function () {
return {
restrict: 'EA',
require: 'ngModel', //require to get access to `ngModelController`
link: function (scope, inputElement, attrs, ngModelCtrl) {
var $icon = $('<i class="fa"></i>');
inputElement.before($icon);
scope.$watch(function(){
return ngModelCtrl.$valid; //made watch on field validation.
}, function(val){
if (val.indexOf("ng-valid") >= 0) {
inputElement.prev().addClass('fa-check green-i');
}
});
}
};
});
I think this will do it for you:
https://stackoverflow.com/a/23871934/1636157
angular.module('mean.theme')
.directive("addIconElement", function () {
return {
restrict: 'EA',
require: '^form',
link: function (scope, inputElement, attrs, ctrl) {
var $icon = $('<i class="fa"></i>');
inputElement.before($icon);
scope.$watch(ctrl.$name + '.' + inputElement.attr('name') + '.$valid', function (valid) {
if(valid) {
inputElement.prev().addClass('fa-check green-i');
} else {
inputElement.prev().removeClass('fa-check green-i');
}
});
}
};
});
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'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');
}
});
}
}]);