I want to create a custom form validation, using AngularJS. That form should have input and select elements. The form should be valid, when either imputs are empty or both filled with some values. Here is the view:
<form name="recipientsForm" novalidate>
<md-input-container>
<label>Name</label>
<input name="name" type="text" ng-model="relationship.name" value="" empty-or-both-filled="relationship.relationshipType">
<div ng-messages="recipientsForm.name.$error">
<div ng-message="emptyOrBothFilled">Enter name.</div>
</div>
</md-input-container>
<md-input-container>
<md-select name="type" placeholder="Select your relation... " ng-model="relationship.relationshipType" empty-or-both-filled="relationship.name">
<md-option ng-repeat="type in relationshipTypes" value="{{type.relationshipType}}">
{{type.name}}
</md-option>
</md-select>
<div ng-messages="recipientsForm.type.$error">
<div ng-message="emptyOrBothFilled">Pick relationship.</div>
</div>
</md-input-container>
</form>
And here is the directive:
(function () {
'use strict';
angular
.module('app')
.directive('emptyOrBothFilled', [emptyOrBothFilled]);
function emptyOrBothFilled() {
return {
restrict: 'A',
required: 'ngModel',
scope: {
targetNgModel: '=emptyOrBothFilled'
},
link: function($scope, element, attrs, ngModel) {
ngModel.$validators.emptyOrBothFilled = function(val) {
var isValueEmpty = !val;
var isTargetEmpty = !$scope.targetNgModel;
return (isTargetEmpty && isValueEmpty) || (!isTargetEmpty && !isValueEmpty);
}
$scope.$watch('targetNgModel', function() {
ngModel.$validate();
})
}
}
}
})();
Prompt, please, why do I get this error:
TypeError: Cannot read property '$validators' of undefined
at link (http://localhost:3000/app/shared/directives/EmptyOrBothFilled.js:17:24)
It should be
require: 'ngModel',
not
required: 'ngModel',
in the directive specification.
Related
I am using angular.js 1.6.4 version. I created a directive for server-side validation and I see that it's firing when I am loading the form, which is wrong. I only want to fire my code when I changed the value. My HTML code is
<div class="col-xs-6">
<div class="controls">
<label class="control-label"
ng-hide="editRetailTrackingForm.barcode.$dirty && editRetailTrackingForm.barcode.$error">
#Labels.barcode:
</label>
<input type="text" name="barcode"
ng-model="currentItem.barcode"
sm-code-unique-validator
table-name="items"
column-to-test="barcode"
error-message="itemBarcodeErrorMessage"
primary-key="currentItem.itemId"
ng-model-options="{ updateOn: 'blur', debounce: { default : 500, blur: 0 }}"
class="form-control"
ng-maxlength="100" />
<div ng-class="{loading:editRetailTrackingForm.barcode.$pending}">#String.Format(Messages.validatingX, Labels.barcode)</div>
<div ng-if="editRetailTrackingForm.barcode.$dirty">
<div ng-messages="editRetailTrackingForm.barcode.$error">
<div ng-message="maxlength">
<label class="field-validation-error control-label-error animate-show">
#String.Format(Messages.cannotExceed, Labels.barcode, "100")
</label>
</div>
<div ng-message="smCodeUnique">
<div class="info-text-block-error">
{{itemBarcodeErrorMessage}}
</div>
</div>
</div>
</div>
</div>
</div>
and my directive code is very similar to http://www.codelord.net/2014/11/02/angularjs-1-dot-3-taste-async-validators/
return {
require: "ngModel",
scope: {
primaryKey: "=?",
tableName: "#",
columnToTest: "#",
errorMessage: "=?"
},
link: function ($scope, element, attrs, ngModel) {
ngModel.$asyncValidators.smCodeUnique = function (modelValue, viewValue) {
if (!viewValue) {
return true;
}
let codeObject = {
id: $scope.primaryKey, tableName: $scope.tableName,
columnToTest: $scope.columnToTest, code: viewValue
};
return services.Http.put('api/items/checkCodeUniqueness', codeObject).then(
function (response) {
if (!response.data.isValid) {
$scope.errorMessage = response.data.errorMessage;
return services.Deferred.reject(response.data.errorMessage);
}
return true;
}
);
};
}
};
When I am debugging my code I see that server side code is running multiple times when I only instantiate my form (and not even open the correct tab where this field is).
So, how should I change my directive or ng-options to only fire validations when I changed my value?
I have any checkboxes, i need put a string "MESSAGE IN THE END" in the end of theses checkboxes.
how can I do it?
<input type="checkbox" ng-model="my_check" validate />
<br>
<input type="checkbox" ng-model="my_check" validate />
<br>
<input type="checkbox" ng-model="my_check" validate />
<br>
<input type="checkbox" ng-model="my_check" validate />
app.directive('validate', function ($timeout,$compile) {
return {
restrict: 'AE',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
if (!ngModel){
return;
}
ngModel.$parsers.push(function(val){
var element_delete= angular.element( document.querySelector( '#errormy_check' ) )
element_delete.remove();
var newDirective = angular.element('<div id="errormy_check">MESSAGE IN THE END</div>');
element.after(newDirective);
$compile(newDirective)(scope);
ngModel.$render();
return false;
})
}
};
});
I need this!
I want to put this message at the end of all checkboxes, every time the user changes the value of a checkbox.
http://jsfiddle.net/w7vy9kbt/
You are removing all message elements instead of a specific one.
var element_delete= angular.element( document.querySelector( '#errormy_check' ) );
it should be,
var element_delete = element.next('#errormy_check');
var app = angular.module('app', []);
app.controller('appCtrl', function($scope) {});
app.directive('validate', function($timeout, $compile) {
return {
restrict: 'AE',
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
if (!ngModel) {
return;
}
ngModel.$parsers.push(function(val) {
var element_delete = element.next('#errormy_check');
element_delete.remove();
var newDirective = angular.element('<div id="errormy_check">MESSAGE IN THE END</div>');
element.after(newDirective);
$compile(newDirective)(scope);
ngModel.$render();
return false;
})
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<section ng-app="app">
<article ng-controller="appCtrl" class="container">
<form class="form-horizontal well" name="form">
<input type="checkbox" ng-model="my_check" validate />
<br>
<input type="checkbox" ng-model="my_check" validate />
<br>
<input type="checkbox" ng-model="my_check" validate />
<br>
<input type="checkbox" ng-model="my_check" validate />
</form>
</article>
</section>
I need to bind inputs of type 'number' with a different models which are strings. I've managed to bind them using a directive like:
app.directive('input', function () {
return {
restrict: 'E',
require: 'ngModel',
priority:999999,
link: function (scope, elem, attrs, ctrl) {
//Check del tipo input
if (attrs.type.toLowerCase() !== 'number')
{
return;
}
//Paso a numero el valor a colocar
ctrl.$formatters.push(function (value)
{
return value ? parseFloat(value) : null;
});
}
};
});
And the HTML is like this:
<input class="form-control" type="number" ng-model="scopeValue" />
Up to here, there is no problem with binding. But, when I write a ng-repeat and ng-switch combined this directive is not executed. Sample code:
<div ng-repeat="attribute in attributes" ng-switch on="attribute.type">
<div class="input-group">
<span class="input-group-addon" id="basic-addon2">{{attribute.label}}</span>
<input class="form-control" ng-switch-when="text" ng-model="attribute.value" type="text" name="{{attribute.label}}" value="{{attribute.value}}">
<input class="form-control" ng-switch-when="number" ng-model="attribute.value" type="number" name="{{attribute.label}}" value="{{attribute.value}}">
</div>
</div>
Here the directive link code is never thrown and the inputs with number are never completed. As far as I know, the directive checks all the inputs and has the ngModel dependence. Why is it never executed?
I have directive like this:
.directive('validRegex', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
ngModel.$parsers.unshift(function(viewValue) {
console.log(viewValue);
try {
var regex = new RegExp(viewValue);
ngModel.$setValidity('notRegex', true);
return viewValue;
} catch(e) {
ngModel.$setValidity('notRegex', false);
return undefined;
}
});
}
};
})
and I use it like:
<div class="col-sm-7">
<input class="form-control" valid-regex id="search-text" type="text" ng-model="selectedSearchText"/>
<span ng-show="selectedSearchText.$error.notRegex" class="form-error">
Invalid Regular Expression
<span class="icon-attention app_icon"></span>
</span>
</div>
<p>{{selectedSearchText}}</p>
If regex is invalid the the text don't show up as expected but no error message. I've search SO but didn't find a fix.
You have to enclose the input field with in a form as follows
<form name="form">
<div class="col-sm-7">
<input class="form-control" valid-regex id="search-text" type="text" ng-model="selectedSearchText" name="selectedSearchText"/>
<span ng-show="form.selectedSearchText.$error" class="form-error">
Invalid Regular Expression
<span class="icon-attention app_icon"></span>
</span>
</div>
<p>{{selectedSearchText}}</p>
</form>
i am using datepicker but here facing problem regarding model value not binding to model when i select date its nothing happen, any one can tell me where i am doing wrong must be appreciated. here i am sending my code.Showing date picker just problem after selecting date value not not binding to ng-model="user.dob".
signUpview.html
<div class="col-md-6">
<label for="datepicker" class="col-lg-5 form-label">Date Of Birth:</label>
<div class="col-lg-7">
<input type="text" class="form-control dateBirth" ng-model="user.dob" id="datepicker" name="datepicker" datepicker placeholder="Date Of Birth" required/>
<div class="error" ng-show="newUser_form.datepicker.$dirty && newUser_form.datepicker.$invalid">
<small class="error errorFields" ng-show="newUser_form.datepicker.$error.required"> Date is required.</small>
</div>
</div>
</div>
datepickerDirective.js
app.directive('datepicker', function() {
var linker = function(scope, element, attrs) {
element.datepicker().on('changeDate', function(){
console.log(scope);
$(".datepicker").hide();
});
}
return {
require: 'ngModel',
restrict: 'A',
link: linker
}
});
you can use ngModel.$setViewValue update the model property
app.directive('datepicker', function() {
var linker = function(scope, element, attrs,ngModelCtrl) {
element.datepicker().on('changeDate', function(){
console.log(scope);
ngModelCtrl.$setViewValue(value);//value is datepicker selected date;
$(".datepicker").hide();
});
}
return {
require: 'ngModel',
restrict: 'A',
link: linker
}
});