Is there a way to make a form invalid if two inputs don't match (like passwords), in Angular? Similar to form.password.$error.required?
pwd1:<input type="password" ng-model="pwd1" required /><br />
pwd2:<input type="password" ng-model="pwd" required /><br />
<div ng-show="pwd1 && pwd">Invalid:
<span ng-show="pwd1!==pwd">Wrong</span>
<span ng-show="pwd1===pwd">Correct</span>
</div>
This just checks if both the passwords are same.
Angular Form validation
Also check this Angular Ui which has password match directive
You can use Angular UI, it has a ui-validate directive:
<input name="password" required ng-model="password">
<input name="confirm_password" ui-validate=" '$value==password' " ui-validate-watch=" 'password' ">
Or, you can build your own directive for that
myApp.directive('matchPassword', function () {
return {
require: 'ngModel',
restrict: 'A',
scope: {
matchPassword: '='
},
link: function (scope, elem, attrs, ctrl) {
scope.$watch(function () {
return (ctrl.$pristine && angular.isUndefined(ctrl.$modelValue)) || scope.matchSenha === ctrl.$modelValue;
}, function (currentValue) {
ctrl.$setValidity('matchPassword', currentValue);
});
}
};
});
and use it like so:
<input required name="passwordConfirm" match-password="model.Password" />
Related
I've written a directive which adds a class based on a condition - see snippet at the bottom of the question.
It works as expected in the following simple usage scenario for a required field:
<input type="text" name="lastName" ng-model="$crtl.lastName" my-directive="$crtl.isLastNameValid()" required>
However in the following scenario where I have two dependent elements using ng-required it blocks input on the element in which I don't type initially.
i.e. if I type in email it blocks input into mobile and visa versa - other than that is works fine, used as:
<input type="email" id="email" name="email" ng-model="$ctrl.emailAddress"
ng-required="$ctrl.mobileNumber.length === 0" my-directive="$ctrl.isEmailValid()">
<input type="tel" id="mobile" name="mobile" ng-model="$ctrl.mobileNumber"
pattern="(?:\+?61|0)4 ?(?:(?:[01] ?[0-9]|2 ?[0-57-9]|3 ?[1-9]|4 ?[7-9]|5 ?[018]) ?[0-9]|3 ?0 ?[0-5])(?: ?[0-9]){5}"
ng-required="$ctrl.emailAddress.length === 0" my-directive="$ctrl.isMobileValid()">
Where am I going wrong? I am compiling the element based on the condition passed in I am assuming it has something to do with that?
export const myDirective = ($compile: ng.ICompileService): ng.IDirective => {
return {
restrict: 'A',
scope: true,
compile: (element: ng.IAugmentedJQuery, attrs: ng.IAttributes): ng.IDirectivePrePost => {
var condition = attrs['myDirective'];
element.removeAttr('my-directive');
if (condition) {
element.attr('ng-class', `{ "validation-error": ${condition} }`);
return {
pre: () => { },
post: ($scope: ng.IScope, element: ng.IAugmentedJQuery) => {
$compile(element)($scope);
}
};
}
return {
pre: () => { },
post: () => { }
};
}
};
};
If you want a directive that adds and removes a class based on a condition defined by an angular expression:
app.directive("myDirective", function () {
return function postLink (scope, elem, attrs) {
scope.$watch(attrs.myDirective, function(newBool) {
if (newBool) {
attrs.$addClass("validation-error");
} else {
attrs.$removeClass("validation-error");
};
});
};
});
On every digest cycle, the directive evaluates the Angular Expression defined by the my-directive attribute and if the expression changes, it either adds or removes the validation-error class based in the truthyness of the Angular Expression.
I have made a directive for an Angular UI typeahead field. I am trying to design it so that as a user is typing, it sends asynchronous backend calls for results that will populate the dropdown that appears, as demonstrated in the Angular-bootstrap docs, example 2. However, when I start typing ('a' in this case), I get the error:
TypeError: Cannot use 'in' operator to search for 'getters' in a
Here is the factory method that makes the REST call:
certFactory.getUsersWithMatchingUsername = function(username) {
return $http.get(urlBase + '/managed/user?_queryFilter=userName+co+' + '\'' + username + '\'', {timeout: timeoutLength})
.then(function(response) {
// success
return response.data;
}, function(response) {
// error
return $q.reject(response);
});
};
Here is the controller method that calls the factory method:
$scope.getters = {
getUsersWithUsername: function (username) {
certFactory.getUsersWithMatchingUsername(username)
.then(function (response) {
var users = [];
angular.forEach(response.result, function(item) {
users.push(item);
})
return users;
}, function (error) {
console.log('failed!')
})
}
Here is my directive:
angular.module('myApp')
.directive('dropdownsearch', function(){
return {
restrict: 'E',
transclude: true,
scope: {
getterFn: '&',
config: '=', // object with properties label and type
disabled: '=?ngDisabled',
required: '=?ngRequred',
ngModel: '=',
options: '='
},
require: ['^form', 'ngModel'],
templateUrl: 'views/templates/dropdownSearchView.html',
replace: true,
link: function(scope, iElm, iAttrs, controller) {
if (iAttrs.required !== undefined) {
// If attribute required exists
// ng-required takes a boolean
scope.required = true;
}
if (iAttrs.readonly !== undefined) {
// If attribute required exists
// ng-required takes a boolean
scope.readonly = true;
}
}
}
}
);
Here is the directive template:
<div class="form-group has-feedback">
<label class="control-label"> Choose {{ config.type }}></label>
<div class="dropdown dropdown">
<div class="input-group">
<input
type="text"
class="form-control"
placeholder="Make selection"
ng-model="ngModel"
uib-typeahead="option as option[config.label] for option in getterFn($viewValue)"
typeahead-editable="false"
ng-required="required"
ng-disabled="disabled"
/>
</div>
</div>
</div>
And finally, here is my directive in use:
<dropdownsearch ng-show= 'fieldMethods.showSubfield(subfield)'
getter-fn="getters.getUsersWithUsername"
ng-model="subsubfield.value"
config="fieldMethods.getConfig(subfield)">
</dropdownsearch>
Any help would be greatly appreciated. Also, let me know if any additional info is required.
The UI Bootstrap website Asynchronous Typeahead example uses uib-typeahead="address for address in getLocation($viewValue)". My guess is that your error message is saying that it's expecting for, not as in the directive. I don't understand this so I could be wrong! :-)
I have this simple form with a text box that is required and a save button.
<form role="form" name="frmVariableConfig" novalidate ng-submit="frmVariableConfig.$valid && vm.saveChanges()">
<input type="text" ng-model="vm.CurrCustomer.Name" name="txtCustomerName" class="form-control input-sm validate[required]" placeholder="txtCustomerName" check-validation>
<button type="submit" class="btn btn-sm text-right">Save</button>
</form>
I'm using this directive to activate the Jquery Validation Engine
angular.module('app').directive('checkValidation', [
function () {
return {
restrict: 'A',
require: '?ngModel',
link: function (scope, element, attrs, ngModel) {
element.closest('form').validationEngine(
{
promptPosition: 'centerRight',
scroll: true, prettySelect: true,
autoPositionUpdate: true,
//validateNonVisibleFields: true,
//autoHidePrompt: true,
autoHideDelay: 1000,
fadeDuration: 0.9
}
);
}
};
}]);
but it keeps on calling saveChanges() even if the text-box is empty. It should not call this function if the text-box is empty.
Please help.
In one project, the only way I found to solve this scenario was to pass the value of $valid to save method.
HTML
ng-submit="vm.saveChanges( frmVariableConfig.$valid )"
JS
$scope.saveChanges = function(valid) {
if(valid) {
//do save
}
}
I want to change the source (e.g source variable) that is managed by input's ngModel from my directive.
I want to clone the object that is editable by a form and make this process in the directive.
Probably this jsfiddle will explain you better.
What I do is:
<div ng-app="myApp">
<div ng-controller="SimpleController">
<form change-original-model>
<input ng-model="myModel.firstname" /><br/>
<input ng-model="myModel.secondname" /><br/>
I want <b>myModel</b> to be not changed:<br/>
{{ myModel.firstname }}<br/>
I want <b>newModel</b> to be cloned and changed by input:<br/>
{{ newModel.firstname }}<br/>
</form>
</div>
angular.module('directives', []);
angular.module('directives').controller('SimpleController', function($scope) {
$scope.myModel = { firstname: 'Sady', secondname: 'Sherozi' };
});
angular.module('directives').directive('changeOriginalModel',
function($parse) {
return {
require: '?ngModel',
link: function(scope, element, attrs, controller) {
var ngModel = $parse(attrs.ngModel)(scope);
scope.newModel = angular.copy(ngModel);
$(element).find("input").each(function(){
form_elements = $(this).attr("ng-model");
if (form_elements) {
var replace_input_data = form_elements.replace(attrs.ngModel + '.', "newModel." );
$(this).attr("ng-model", replace_input_data);
}
});
}
};
}
);
angular.module('myApp', ['directives']);
I find this example step-by-step form with bootstrap and angularjs
How can I validate the email before jump to step 2 ??
or block the step jump until the fields are full??
function RegisterCtrl($scope, $location) {
$scope.steps = [
'Step 1: Team Info',
'Step 2: Campaign Info',
'Step 3: Campaign Media'
];
....some code
First, define your model in your controller:
function RegisterCtrl($scope, $location) {
$scope.step1 = {
name: '',
email: '',
password: '',
passwordc: ''
};
//...
Bind it to your form fields:
<input type="text" id="inputEmail" ng-model="step1.email" placeholder="Email">
Next, do your validation inside gotoStep():
$scope.goToStep = function(index) {
if (!$scope.step1.email.match(/[a-z0-9\-_]+#[a-z0-9\-_]+\.[a-z0-9\-_]{2,}/)) {
return window.alert('Please specify a valid email');
}
//...
Obviously alert is not great so use jQuery to focus() and add the Bootstrap classes (control-group warning) to highlight the field.
http://jsfiddle.net/xayzP/
You should use directives to test your form field vadility, e.g:
app.directive('email', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function(viewValue) {
if (viewValue && viewValue.match(/[a-z0-9\-_]+#[a-z0-9\-_]+\.[a-z0-9\-_]{2,}/)) {
// it is valid
ctrl.$setValidity('email', true);
return viewValue;
} else {
// it is invalid, return undefined (no model update)
ctrl.$setValidity('email', false);
return undefined;
}
});
}
};
});
In your html, you need to add the directive to your input field. You can show error messages if a field is not valid using the myForm.email.$error object:
<input type="text" name="email" id="inputEmail" placeholder="Email" ng-model="email" email required>
<span ng-show="myForm.email.$error.email" class="help-inline">Email invalid</span>
<span ng-show="myForm.email.$error.required" class="help-inline">Email required</span>
You can disable the next link until the form is valid by using myForm.$invalid on ng-class:
<li ng-class="{disabled: myForm.$invalid}" >
<a ng-model="next" ng-click="incrementStep(myForm)">Next Step →</a>
</li>
See example.