I have a problem with showing error message when the user enters a wrong number. I tried to write my own directive for that but i m getting an error
"Cannot read property 'value' of undefined".
I m totally a newbie, just trying to learn directives. Any idea where did i made a mistake or how should i made it ?
Template :
<div ng-controller="performanceController">
<input type="number" name="performance" class="typo-xl-l input-power"
ng-model="performance" min-performance="10" max-performance="30">
<span id = "errorText"></span>
</div>
Controller :
'use strict';
angular.module('myApp', [
'ngRoute'
]).
config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'partials/inputView.html'
})
}])
.controller('performanceController', function($scope) {
})
.directive("maxPerformance", [function() {
return {
restrict: "A",
link: function(scope, elem, attrs) {
var limit = parseInt(attrs.maxPerformance);
if (this.value.length > limit) {
document.getElementById('errorText').innerText("wrong number");
}
}
}
}])
.directive("minPerformance", [function() {
return {
restrict: "A",
link: function(scope, elem, attrs) {
var limit = parseInt(attrs.minPerformance);
if (this.value.length < limit) {
document.getElementById('errorText').innerText("wrong number");
}
}
}
}]);
UPDATE :
.directive("maxPerformance", [function() {
return {
restrict: "A",
require: 'ngModel', //this will make ng-model attribute compulsary on directive element.
link: function(scope, elem, attrs, ngModel) { //injected ngModel here 4th parameter
var limit = parseInt(attrs.maxPerformance);
angular.element(elem).on("keydown", function() {
if (ngModel.$viewValue.length > limit) {
document.getElementById('errorText').innerText("wrong number");
}
});
}
}
}])
.directive("minPerformance", [function() {
return {
restrict: "A",
require: 'ngModel',
link: function(scope, elem, attrs, ngModel) { //injected ngModel here 4th parameter
var limit = parseInt(attrs.minPerformance);
angular.element(elem).on("keydown", function() {
if (ngModel.$viewValue.length < limit) {
document.getElementById('errorText').innerText("wrong number");
}
});
}
}
}]);
Still not working..
While getting the value of ngModel inside your directive you could actually have require: ngModel option inside directive which will give ngModelController value inside link function. And then easily you could fetch value of it using ngModel.$viewValue
.directive("maxPerformance", [function() {
return {
restrict: "A",
require: 'ngModel', //this will make ng-model attribute compulsary on directive element.
link: function(scope, elem, attrs, ngModel) { //injected ngModel here 4th parameter
var limit = parseInt(attrs.maxPerformance);
if (ngModel.$viewValue.length > limit) {
document.getElementById('errorText').innerText = "wrong number";
}
}
}
}])
.directive("minPerformance", [function() {
return {
restrict: "A",
require: 'ngModel',
link: function(scope, elem, attrs, ngModel) { //injected ngModel here 4th parameter
var limit = parseInt(attrs.minPerformance);
if (ngModel.$viewValue.length < limit) {
document.getElementById('errorText').innerText = "wrong number";
}
}
}
}]);
Update
Rather going for creating custom directive, you could handle such a small thing by using ng-min & ng-max attributes on the input element which is of type="number".
<form name="myForm" ng-controller="performanceController">
<input type="number" name="performance" class="typo-xl-l input-power" ng-model="performance" min="10" max="30" />
<span id="errorText" ng-show="myForm.performance.$error.min || myForm.performance.$error.max">
Wrong Number
</span>
</form>
Demo Plunkr
Related
Issue is that only the first directive is working and other one is not. Provided below are the two directives. Both works fine when working alone.
.directive("restrictInvalidInput", function($rootScope, utils) {
return {
restrict: "A",
require: "ngModel",
priority: 1,
link: function(scope, elem, attr, ctrl) {
var remove_invalid_chars = function() {
//blah blah
};
ctrl.$parsers.push(remove_invalid_chars);
}
}
})
.directive("validateUsername", function($rootScope, utils) {
return {
restrict: "A",
require: "ngModel",
priority: 2,
link: function(scope, elem, attr, ctrl) {
var validate_username = function(modelValue, viewValue) {
//blah blah
};
ctrl.$validators.valid_username = validate_username;
}
}
});
Seems like the problem is where you put blah blah. Are you sure, that parser returns a value? Because (from docs):
Returning undefined from a parser means a parse error occurred. In that case, no $validators will run
WORKING PLUNKER
angular.module('app', [])
.controller('Controller', ['$scope', function($scope) {
$scope.name = 'Some name';
}])
.directive("restrictInvalidInput", function() {
return {
restrict: "A",
require: "ngModel",
priority: 1,
link: function(scope, elem, attr, ctrl) {
var remove_invalid_chars = function(viewValue) {
console.log('Look, I\'m parsing');
return viewValue;
};
ctrl.$parsers.push(remove_invalid_chars);
}
}
})
.directive("validateUsername", function() {
return {
restrict: "A",
require: "ngModel",
priority: 2,
link: function(scope, elem, attr, ctrl) {
var validate_username = function(modelValue, viewValue) {
console.log('Look, I\'m validating');
return true;
};
ctrl.$validators.valid_username = validate_username;
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="Controller">
<input type="text"
ng-model="name"
restrict-invalid-input
validate-username
/>
{{name}}
</div>
</div>
I'm trying to get the value from one of the input fields in my form, but my code isn't working:
JavaScript:
angular
.module('myDirectives')
.directive('pwMatch', matchPassword);
function matchPassword() {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
var modelIt = attrs.pwMatch;
var inputValue = attrs.modelIt;
console.log(inputValue);
}
};
};
HTML:
<input name="telephone" type="number" value="223344455">
<div pw-match="form.telephone"></div>
If you are trying to get the value of an input, use ng-model.
<input ng-model="form.telephone" type="number" value="223344455">
<div pw-match input-name="form.telephone"></div>
And if you want to get that value in a directive using a name on an attribute, use the$watch method on the scope.
JS
angular.module('myDirectives',[])
.directive('pwMatch', function() {
return {
restrict: 'A',
link: function (scope, element, attrs) {
scope.$watch(attrs.inputName, function(value) (
var inputValue = value;
console.log(inputValue);
};
}
}
});
.module('myDirectives')
needs to be
.module('myDirectives', [])
Even though you have no dependencies, you have to have the empty array.
Also, it's a really bad idea™ to use a variable function as a directive or something, it's just going to confuse you.
This works, too, and might make your application a bit easier to maintain:
angular.module('myDirectives', [])
.directive('pwMatch', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
var modelIt = attrs.pwMatch;
var inputValue = attrs.modelIt;
console.log(inputValue);
}
}
});
I am trying to add an input directive in order to trim all text inputs. So far this is the code of my directive:
app.directive("input", function directive() {
return {
restrict: "E",
priority: 1,
require: "ngModel",
link: function link(scope, element, attrs, ctrl) {
element.on("focusout", function triggerChange(event) {
var input = event.target;
if (input.value && input.type === "text") {
ctrl.$setViewValue(input.value.trim());
ctrl.$render();
}
});
}
};
});
My issue is that the ngModel does not seem to be injected, as I get the error:
Error: [$compile:ctreq] Controller 'ngModel', required by directive 'input', can't be found!
Any idea why this happens, and how to fix it?
Update:
Actually, this is the interaction of Kendo Grid and AngularJS. The input I am testing is generated by Kendo Grid. The code of the column is standard:
{ field: "name", title: "titleName" }
You must have some input element in your HTML which does not have ng-model.
You can change your code to require: "?ngModel", and later check if ctrl is undefined or not, like:
app.directive("input", function directive() {
return {
restrict: "E",
priority: 1,
require: "?ngModel",
link: function link(scope, element, attrs, ctrl) {
if (!ctrl) { return ;}
element.on("focusout", function triggerChange(event) {
var input = event.target;
if (input.value && input.type === "text") {
ctrl.$setViewValue(input.value.trim());
ctrl.$render();
}
});
}
};
You should have provided ng-model in your html when you use this directive because you wrote require: 'ngModel', in the directive. so in your case your directive name is input so it will be something like
<input ng-model="something"> </input>
My answer is not perfect, but it is the best I could find:
app.directive("input", function directive() {
return {
restrict: "E",
priority: 1,
require: "ngModel",
link: function link(scope, element, attrs, ctrl) {
element.on("focusout", function triggerChange(event) {
var input = $(event.target);
input.val(input.val().trim());
input.trigger("change");
});
}
};
});
So basically, we trim the input, and use input.trigger("change") to inform the system that the input has changed.
A warning though, it does not work with our validation system (valdr).
I have a directive and I'm trying to pass Date/moment object via attribute. I'm passing it like this: (I know, that I can create isolated-scope and bind it, it is not the case)
<form name="form">
<input name="field" ng-model="fieldModel" form-field-directive field-date="{{fieldDateModel}}" />
</form>
Without curly brackets the result is obvious, but with I'm getting such quoted string "2015-07-03T10:35:13.691Z".
Is there anyway to work with it?
UPDATE:
angular.module('app', [])
.controller('AppCtrl', function($scope) {
$scope.fieldDateModel = moment(); // new Date()
});
angular.module('app')
.directive('formFieldDirective', function() {
return {
restrict: 'A',
require: '^ngModel',
link: function(scope, iElement, iAttrs, ngModelCtrl) {
ngModelCtrl.$validators.fieldDate = function() {
if (angular.isUndefined(iAttrs.fieldDate)) {
return true;
}
console.log(iAttrs.fieldDate);
};
}
};
});
You can actually pull the value from the parent scope using $parse which is more reliable.
angular.module('app')
.directive('formFieldDirective', function($parse) {
return {
restrict: 'A',
require: '^ngModel',
link: function(scope, iElement, iAttrs, ngModelCtrl) {
ngModelCtrl.$validators.fieldDate = function() {
if (angular.isUndefined(iAttrs.fieldDate)) {
return true;
}
console.log(($parse(iAttrs.fieldDate)(scope)).format());
};
}
};
});
http://jsbin.com/qoheraloge/1/edit?js,console,output
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;
}
});
}
};
})