I am trying to display value of all my fields in a json object .I am able to add firstname ,email , password in an object.but my confirm password not displaying in object why ? I enter same password with confirm password still not display
here is my code
http://plnkr.co/edit/iHA8iQC1HM5OzZyIg4p3?p=preview
angular.module('app', ['ionic','ngMessages']).directive('compareTo',function(){
return {
require: "ngModel",
scope: {
otherModelValue: "=compareTo"
},
link: function(scope, element, attributes, ngModel) {
ngModel.$validators.compareTo = function(modelValue) {
// alert(modelValue == scope.otherModelValue)
return modelValue == scope.otherModelValue;
};
scope.$watch("otherModelValue", function() {
ngModel.$validate();
});
}
};
why confirm password not display ?
}).controller('first',function($scope){
})
Your compareTo directive fails and it will not bind to a model if the validator is failing. If you remove your compareTo directive from the code you will get the confiredpassword in your scope.
Refer to this: password-check directive in angularjs to fix your comparTo directive.
Also here is a plunker of the fixed directive:
http://plnkr.co/edit/wM3r6eR2jhQS7cjvreLo?p=preview
.directive('compareTo', function() {
return {
scope: {
targetModel: '=compareTo'
},
require: 'ngModel',
link: function postLink(scope, element, attrs, ctrl) {
var compare = function() {
var e1 = element.val();
var e2 = scope.targetModel;
if (e2 !== null) {
return e1 === e2;
}
return false;
};
scope.$watch(compare, function(newValue) {
ctrl.$setValidity('errorCompareTo', newValue);
});
}
};
Related
I'm trying to write a custom directive to validate input value: does it belong to the specified range. The problem is that I can't access ng-model without knowing the name of the scope variable which is used for ng-model. Considering that directive has to be reused with different inputs I want to access ng-model directly. I did try to use scope[attrs.ngModel] but got the undefined value. How can read ng-model value inside directive? Thank you.
netupApp.directive('between', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
scope.$watch('dataSubmitting', function(dataSubmitting){
if (dataSubmitting) {
var min = Number(attrs.min);
var max = Number(attrs.max);
console.log(attrs.ngModel); // "number"
console.log(scope[attrs.ngModel]); // undefined
var inputText = scope.number; // that is the var used in ng-model
console.log(min); // 10
console.log(inputText); // would be the input value
console.log(max); //20
if (inputText <= min || inputText >= max) {
scope.alerts.push({
msg: 'error',
type: 'danger',
icon: 'warning',
'closable': true
});
}
}
});
}
};
});
You should hook into the Angular validation system and add your validator function to either the $validators or $asyncValidators collections (in your case I think $validators is enough, no need for async).
The validator functions receive the model value as an argument :
link: function(scope, elm, attrs, ctrl) {
var min = Number(attrs.min);
var max = Number(attrs.max);
ctrl.$validators.between = function(modelValue, viewValue) {
if (modelValue <= min || modelValue >= max) {
//do something here or just return false
return false;
}
return true;
}
}
In the view you can get the validation error messages like this :
<div ng-messages="formName.inputName.$error">
<p ng-message="between">The value is not in the required range<p>
</div>
Reference doc : https://docs.angularjs.org/api/ng/type/ngModel.NgModelController
The proper way to get the ngModel.$viewValue is:
app.directive('between', function () {
return {
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
ngModel.$render = function () {
var newValue = ngModel.$viewValue;
console.log(newValue)
};
}
};
});
Have a look at tutorial underneath when wanting to invoke the ngModel.$setViewVAlue from the directive
https://egghead.io/lessons/angularjs-using-ngmodel-in-custom-directives
According to angluarJs doc:$parse
you need to parse the attrs, please try:
var getter=$parse(attrs.ngModel);
var setter=getter.assign;
setter(scope,getter(scope));
I have created a complex form element to avoid code duplication.
However I can't make it to behave same as normal input field.
HTML
<input name="first" ng-model="ctrl.first" type="text" required is-number />
<complex-input name="second" ng-model="ctrl.second" required></complex-input>
JS/ng
// main input directive
app.directive("complexInput", function(){
return {
require: "^?ngModel",
scope: {
passedModel: '=ngModel'
},
template: "<div><input ng-model='passedModel' is-number type='text' child-element /></div>",
link: function(scope, elem, attr, modelCtrl) {
angular.extend(modelCtrl.$validators, scope.childValidators || {});
}
}
});
// is number validator
app.directive('isNumber', function(){
return {
require: "^?ngModel",
link: function(scope, elem, attr, modelCtrl) {
modelCtrl.$validators.isNumber = function (modelValue, viewValue) {
var value = modelValue || viewValue;
return !isNaN(value);
};
}
}
});
// hacky directive to pass back validators from child field
app.directive('childElement', function(){
return {
require: "^?ngModel",
priority: 10,
link: function(scope, elem, attr, modelCtrl) {
if (!modelCtrl) return;
scope.childValidators = modelCtrl.$validators;
}
}
});
When I run it content of both fields errors is following.
On init:
First: {"required":true}
Second: {"required":true}
If I enter string:
First: {"isNumber":true}
Second: {**"required":true**,"isNumber":true}
If I enter number:
First: {}
Second: {}
I would expect both input and complex-inputto behave same. Problem is obviously that is-number validation on inner input is blocking model on outer complex-input so it's value is not set, unless you enter number.
What am I doing wrong?
Is there a nicer/cleaner way to do this and possibly avoid the ugly childElement directive?
Please find test plnkr here: https://plnkr.co/edit/Flw03Je1O45wpY0wf8om
UPDATE: Complex input is not a simple wrapper for input. In reality in can have multiple inputs that together compile a single value.
You can solve both problems (the childElement and the correct validation) by letting complex-element be only a wrapper around the real input field.
To do this :
The complex-element directive has to use something else than name, for example "input-name"
The input in the complex-element directive template need to use that name
You need to pass from complex-element to the input field whatever else you need (validations, events etc..)
For example, the following is your code modified and works as you expect :
var app = angular.module("myApp", []);
app.controller("MyCtrl", function($scope){
var vm = this;
vm.first = "";
vm.second = "";
});
app.directive("complexInput", function(){
return {
require: "^?ngModel",
scope: {
passedModel: '=ngModel',
name: '#inputName'
},
template: "<div><input ng-model='passedModel' name='{{name}}' is-number type='text'/ required></div>",
link: function(scope, elem, attr, modelCtrl) {
angular.extend(modelCtrl.$validators, scope.childValidators || {});
}
}
});
app.directive('isNumber', function(){
return {
require: "^?ngModel",
link: function(scope, elem, attr, modelCtrl) {
modelCtrl.$validators.isNumber = function (modelValue, viewValue) {
var value = modelValue || viewValue;
return !isNaN(value);
};
}
}
});
HTML
<p>COMPLEX:<br/><complex-input required input-name="second" ng-model="ctrl.second"></complex-input></p>
See the plunker here : https://plnkr.co/edit/R8rJr53Cdo2kWAA7zwJA
Solution was to add ng-model-options='{ allowInvalid: true }' on inner input.
This forces inner input to update model even if it's invalid.
However more nicer solution would be to pass entire model from child elements to parent directive and then iterate through their $validators.
app.directive('childElement', function(){
return {
require: "^?ngModel",
priority: 10,
link: function(scope, elem, attr, modelCtrl) {
if (!modelCtrl) return;
scope.childModels.push(modelCtrl);
}
}
});
Complex input here has two inputs that combined give a final value.
First one has to be number but it's not required, while the second one is required.
app.directive("complexInput", function(){
function preLink(scope, elem, attr, modelCtrl) {
// create local scope value
scope.inner1 = "";
scope.inner2 = "";
scope.childModels = [];
}
// do some nice mapping of inner errors
function mapKeys(index, validator) {
return validator + "." + index;
}
function postLink(scope, elem, attr, modelCtrl) {
// copy value on change to passedModel
// could be complex state
scope.$watch('inner1', function(value){
scope.passedModel = scope.inner1 + scope.inner2;
});
scope.$watch('inner2', function(value){
scope.passedModel = scope.inner1 + scope.inner2;
});
scope.childModels.forEach(function(childModel, index){
childModel.$viewChangeListeners.push(function(){
Object.keys(childModel.$validators).forEach(function(validatorKey){
modelCtrl.$setValidity(mapKeys(index, validatorKey), !childModel.$error[validatorKey]);
});
});
});
}
return {
require: "^?ngModel",
scope: {
passedModel: '=ngModel'
},
template: "<div><input ng-model='inner1' is-number type='text' child-element /><br/><input ng-model='inner2' required type='text' child-element /></div>",
compile: function(element, attributes){
return { pre: preLink, post: postLink };
}
}
});
I am using angular-country-select module.
I am not able to set the default selected value to the dropdown.
<input country-select data-ng-model="userCtrl.country" class="signup-country" placeholder="Country*" ng-required="true" name="country" id="signUpCountry" value="{{userCtrl.country}}">
I tried to modify the module code to pass the val to select2 (as this module used select2). Below is the modified code:
angular.module('angular-country-select', [])
.directive('countrySelect', [function() {
return {
restrict: 'A',
require:'ngModel',
link: function(scope, elem, attrs, ngModelCtrl) { console.log("elem");
var data = ["id":"AX","text":"Åland Islands"},{"id":"AL","text":"Albania"}, ....]; //This array has values
var defaultValue = attrs.value || '';
ngModelCtrl.$setViewValue(defaultValue);
var select2Inst = elem.select2({
data: data,
val: defaultValue
});
}
};
}]);
But this also does not select the default value.
Any help is appreciated.
I was able to select the default by adding $timeout
Below is updated module code:
angular.module('angular-country-select', [])
.directive('countrySelect', ['$timeout', function($timeout) {
return {
restrict: 'A',
require:'ngModel',
link: function(scope, elem, attrs, ngModelCtrl) { console.log(attrs, attrs.placeholder);
var data = [{"id":"AF","text":"Afghanistan"},{"id":"AX","text":"Åland Islands"},...];
var select2Inst = elem.select2({
data: data
});
$timeout(function() {
if (attrs.value != '') {
ngModelCtrl.$setViewValue(attrs.value);
scope.$apply(select2Inst.select2('val', attrs.value));
}
}, 2000);
}
};
}]);
For all input fields with the type of url (input[type=url]), on blur I wish to check if the value of an input contains http:// or https:// and if it does not to add http:// to the beginning of the user inputted value. Similar to the below jquery:
$('.txtUrl').blur(function(e) {
if ($(this).val().match(/^http/) || $(this).val().match(/^https/)) {
$.noop()
}
else {
// get value from field
var cur_val = $(this).val();
// do with cur_val
$(this).val('http://' + cur_val);
}
});
How do I do this the angular way?
You could do the same functionality using angular directive.
Define ng-model that will take care of ng-model value.
Markup
<input type="url" my-directive ng-model="myUrl"/>
Directive
app.directive('myDirective', function() {
return {
restrict: 'AE',
require: 'ngModel',
link: function(scope, element, attrs, ctrl) {
var model = $parse(attrs.ngModel)
element.on('blur', function(e) {
var value = ctrl.$modelValue; //ngModel Value
if (value.match(/^http/) || value.match(/^https/)) {
angular.noop()
} else {
// assign value to $modelValue
model.assign(scope, 'http://' + value);
}
});
}
}
});
This could help you, Thanks.
I have a directive that is designed to be assigned to a normal text input.
<input type="text" ng-model="fooModel" foo-input size="30"
placeholder="insert value"></input>
I have lots of validation functions for it like testing the precision of the numbers and I use a $parsers to control the value that is submitted.
myApp.directive('fooInput', function () {
return {
restrict: 'A',
require: 'ngModel',
controller: function ($scope, $element, $attrs) {
this.errorMessage = ""
},
link: function (scope, element, attrs, ctrl)
return ctrl.$parsers.push(function (inputValue) {
var originalVal = element.val();
if (!testForOverPrecision(numericVal)) {
//do something here to set the directive as invalid
}
if (originalVal != inputValue) {
ctrl.$setViewValue(res);
ctrl.$render();
}
});
I have 2 questions:
How do I get this to work with the isValid service and do I have to have a controller scope for the error message
Is it correct for me to push the $parser inside a return statement
I am using Angular 1.2x and I created a directive to determine if the text contains the # symbol.
.directive('noAt', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function(viewValue) {
if (/#/.test(viewValue)) {
ctrl.$setValidity('noAt', false);
return undefined;
} else {
ctrl.$setValidity('noAt', true);
return viewValue;
}
});
}
};
})