I have a form with input fields. One input field allows alphanumeric values. But if the value contains letters, then the letters have to be uppercase. How can I implement this approach? Is it possible to define this in the input field, when the user does an input then the letters are automatically shown in uppercase?
The View:
<div class="form-group-sm has-feedback">
<label class="control-label" for="article-id">Article Nr.</label>
<input type="text"
class="form-control"
name="Article"
id="article-id"
ng-model="selected.article"
ng-pattern="/^[a-zA-Z]{2}[a-zA-Z\d]{9}[0-9]$/"
ng-required="true"
/>
</div>
...
//the other inputs are the same definition
It is important for me to save the value in the DB with uppercase letters.
Just create a simple directive ,this answer is based on the answer here: Angular.js: How to autocapitalize an input field?.
myApp.directive('capitalize', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
var capitalize = function(inputValue) {
if(inputValue == undefined) inputValue = '';
var capitalized = inputValue.toUpperCase();
if(capitalized !== inputValue) {
modelCtrl.$setViewValue(capitalized);
modelCtrl.$render();
}
return capitalized;
}
modelCtrl.$parsers.push(capitalize);
capitalize(scope[attrs.ngModel]); // capitalize initial value
}
};
});
HTML like -
<input type="text" ng-model="name" capitalize>
The first Answer works fine. But I've solved this with this CSS code:
CSS:
#article-id {
text-transform: uppercase;
}
Related
I'm using Angular JS v1.5.5 and defined a custom input field type currency that allows entering large numbers as e.g. 1.5k or 3.4M or 4T etc. This I accomplished defining a custom directive currency. The problem is that even when the display value is shown and the model contains a valid value, and when pressing form submmit I get the You must enter a valid value error.
This is the input field configuration as shown using the IE DOM explorer:
<div class="input-group">
<input name="tradeParameters.tradeNotional" class="form-control ng-not-empty ng-valid ng-valid-required ng-dirty ng-valid-number ng-touched" id="tradeParameters_tradeNotional" required="required" type="number" step="1.0E-5" value="" ng-model="inSampleFormData.tradeParameters.tradeNotional" ng-required="true" currency="">
<span class="input-group-addon">$</span>
</div>
The MainModule.ts defines the filter and directive as follows:
.filter('identity', ['$filter', function ($filter) {
return function(input) {
return input;
};
}])
.directive("currency", function($filter, formatServices: FormatServices){
var p = function(viewValue){
if (angular.isDefined(viewValue)) {
return $filter('identity')(formatServices.currParse(viewValue));
}
};
var f = function(modelValue){
if (angular.isDefined(modelValue)) {
return $filter('identity')(formatServices.currFormat(modelValue));
}
};
return {
require: 'ngModel',
link: function(scope, ele, attr, ctrl){
ctrl.$parsers.unshift(p);
ctrl.$formatters.unshift(f);
}
};
})
Basically what I need to be able to register two types of code. The code type A has only numbers and the code Type B has numbers, one hyphen, one alphabetic value and one numeric value.
Hypothetical situation:
I register the code type A, the custom directive validate all values.
I need to register the code type B, I check the option 'Validate code
Type B', the pattern is changed in order to make the validation, then all values entered are validated.
Code - Type A
12345678
32445678
56535678
Code with complement number - Type B
32445678-a1
32445678-a2
65434567-b1
The form
<form>
<span>Insert code:</span><br/>
<input type="text" data-ng-model="code" code-type> <br/>
<input type="checkbox" data-ng-model="validateCodeTypeB" /> Validate code Type B
</form>
Note: When the 'validateCodeTypeB' option is checked the regex will be changed too. But I don't know how to implement the second regex in order to validate the code Type B.
See the example
And the directive
app.directive('codeType', function () {
return {
require: 'ngModel',
link: function (scope, element, attr, ngModelCtrl) {
function codeTypeA(text) {
if (text) {
var transformedInput = text.replace(/[^0-9]/g, '');
if (transformedInput !== text) {
ngModelCtrl.$setViewValue(transformedInput);
ngModelCtrl.$render();
}
return transformedInput;
}
return undefined;
}
ngModelCtrl.$parsers.push(codeTypeA);
}
}
});
Here I have made you plnkr for your solution:
if(!scope.codeType){
transformedInput = text.replace(/[^0-9]/g, ''); // For CodeTypeA
} else {
transformedInput = text.replace(/[^a-z]/g,''); // For CodeTypeB, change it to your own regex
}
https://plnkr.co/edit/IfIeXhy7vZacLi2jKsMs?p=preview
but regex is different for CodetypeB , change it to your regex for codetypeB and its good to go.
So I am new to Angular.
What I want to do is to force an input field (text) to be as the following:
*Uppercase only, or change the letters to uppercase automatically
*Max 30 characters
*No special characters
If someone tries to insert a special character it won't be displayed at all.
So it's not only validation.
It's accepting those rules on the input.
And I want all of this to be done on that field on a specific condition: let's say when the placeholder is equal to "Nickname" which is in my model formField.CustomFieldName
Thank you in advance
There are at least two ways you can do. Use ng-keypress to either check each character you enter or check regular expression on the input.
I am not going to give the entire solution but you can go from here.
<div ng-app="myApp">
<div ng-controller="myController">
<input type="text" ng-model="yourInput" ng-keypress="yourKeypressFunction($event)">
</div>
</div>
In your js:
var myApp = angular.module('myApp',[]);
myApp.controller('myController', ['$scope', function($scope) {
$scope.yourInput = "";
$scope.yourKeypressFunction = function(event) {
console.log(event); // check for event.which, if it is not the char you want, return;
console.log($scope.yourInput); // check for regular expression
}
}]);
https://docs.angularjs.org/api/ng/directive/ngKeypress
Try onchange event and write a method in the component that you are looking to do, or if you are using observables then try to use the observable methods to transform your input to your requirement.
Check this link http://blog.angular-university.io/introduction-to-angular-2-forms-template-driven-vs-model-driven/
This has good explanation how to deal with forms and input fields
you can do it like this using jQuery for restriction of characters
$("#youTextFieldId").keypress(function(e)
{
var code = e.which || e.keyCode;
// 65 - 90 for A-Z and 97 - 122 for a-z 95
if (!((code >= 65 && code <= 90) || !(code >= 97 && code <= 122) )
{
e.preventDefault();
}
});
and for your text limit
<input id="youTextFieldId" type="text" maxlength="30" style="text-transform:uppercase">
try to use ng-pattern=you pattern with maxlength in your text field. for eg:
<input type="text" ng-pattern="/^[a-zA-Z0-9]*$/" maxlength="30">
The /^[a-zA-Z0-9]*$/ will allow you to enter only character and numbers only. not any special characters.
Use https://github.com/candreoliveira/ngMask with a little study of documentation your pattern is very easy to create and it will also force that the user inputs the desired pattern only and on top of that you can just write maxlength="30" ,input type="text"
Look out at this example for better understanding in the demo of the ngMask ngMask String Example Demo
So this is the solution to this problem.
I hope it helps someone.
I made a fiddle for this: http://jsfiddle.net/m152d0t9/
var app = angular.module("myApp", []);
function Fiddle($scope) {}
app.directive('customInputFormat', function() {
return {
restrict: 'A',
require: '?ngModel',
scope: {
customInputFormat: '='
},
link: function(scope, elm, attr, ctrl) {
if (!ctrl) {
return;
}
scope.$watch(attr.ngModel, function(newVal, oldVal) {
if (!scope.customInputFormat) {
return;
}
if (newVal && newVal.length) {
var newStr = newVal.replace(/[^a-zA-Z0-9\s]*/g, '').toUpperCase();
if (newStr.length > 20) {
newStr = newStr.substring(0, 20);
}
ctrl.$setViewValue(newStr);
ctrl.$render();
}
})
}
};
});
And for the HTML:
<ul ng-controller="Fiddle">
<li>
<label data-ng-init="condition = true;" for="foobar"> Input text</label>
<input custom-input-format="condition" id="foobar" name="foobar" type="text" ng-model="foo" required />
</li>
</ul>
I would like to make my service be able to handle any input field. At the moment I am manually writing everything and it's starting to amount to a lot of manual work. Is there a way to send the element object when the elements ng-change property is invoked? I can then change the elements ng-class as a result of that.
Html:
<input type="text" id="email" data-ng-model="email" data-ng-change="changeEmail()" placeholder="your email here" data-ng-class="emailFormControlColor">
In the controller:
$scope.changeEmail = function () {
if ($checkInput.checkEmail($scope.email)) {
// email input is good
$scope.emailFormControlColor = 'form-control-success'; // change from error to success
} else {
// email input is bad
if ($scope.emailFormControlColor === 'form-control-success')
$scope.emailFormControlColor = 'form-control-error'; // change from success to error
}
};
The service (this is included in the controller arguments ofc.):
.service('checkInput', ['$controller', '$window', '$location', function ($controller, $window, $location) {
return {
checkEmail: function (email) {
// <--- I would like to update the ng-class of the focused element here! This would result in me not manually having to write code for each input!
var regex = /^[^\s#]+#[^\s#]+\.[^\s#]+$/;
return regex.test(email);
}
};
}])
The code above is how i have it now. As you can see I'm manually changing the $scope.emailFormControlColor.
Imagine I have three input fields:
<input type="text" id="email1" data-ng-model="email1" data-ng-change="changeEmail()" placeholder="your email here" data-ng-class="emailFormControlColor1">
<input type="text" id="email2" data-ng-model="email2" data-ng-change="changeEmail()" placeholder="your email here" data-ng-class="emailFormControlColor2">
<input type="text" id="email3" data-ng-model="email3" data-ng-change="changeEmail()" placeholder="your email here" data-ng-class="emailFormControlColor3">
How could I write my service so that I do not have the write the following manually:
$scope.emailFormControlColor1 = 'form-control-success';
$scope.emailFormControlColor2 = 'form-control-success';
$scope.emailFormControlColor3 = 'form-control-success';
I hope my question is clear, otherwise say and I'll update it!
I think using a directive to solve this problem is more desirable. For one, it's considered an anti-pattern to modify the DOM in a controller or a service.
The other reason is that when you use a directive, you will be provided the DOM element that the directive was used on. Here's some untested code that you might use as a starting point:
myModule.directive('checkEmail', function() {
require: 'ngModel',
link: function(scope, element, attributes, ngModelController) {
// require that ng-model is used on this element, so you can hook
// into the Angular validator pipeline ...
ngModelController.validators.checkEmail = function(modelValue, viewValue) {
// now return true or false if viewValue is considered valid
var regex = /^[^\s#]+#[^\s#]+\.[^\s#]+$/;
var isValid = regex.test(viewValue);
// but you also have an opportunity to do your DOM manipulation
element.toggleClass('form-control-success', isValid);
element.toggleClass('form-control-error', !isValid);
return isValid;
});
}
});
Instead of applying the CSS class as above, you could just use Angular's built in validation system. Your directive code is the same as above, except you don't apply any CSS classes in the directive. When the validation code in the directive returns false, Angular will make the field invalid ... and you can use this fact to apply the CSS in your HTML:
<form name="myForm">
<input ng-model="whatever"
name="email"
check-email
ng-class="{'form-control-success': myForm.email.$valid, 'form-control-error': myForm.email.$invalid}">
</form>
The above applies the CSS anytime the field is invalid, but you can also apply it when a specific validation error occurs, in this cased we named the validator "checkEmail", so this also would work:
<form name="myForm">
<input ng-model="whatever"
name="email"
check-email
ng-class="{'form-control-success': !myForm.email.$error.checkEmail, 'form-control-error': myForm.email.$error.checkEmail}">
</form>
I would create an object that contains all of the information you need for each email. Something like this:
HTML:
<input type="text" id="email0" data-ng-model="emails[0].value" data-ng-change="changeEmail(emails[0])" placeholder="your email here" data-ng-class="emails[0].class">
<input type="text" id="email1" data-ng-model="emails[1].value" data-ng-change="changeEmail(emails[1])" placeholder="your email here" data-ng-class="emails[1].class">
<input type="text" id="email2" data-ng-model="emails[2].value" data-ng-change="changeEmail(emails[2])" placeholder="your email here" data-ng-class="emails[2].class">
JavaScript:
$scope.emails = [
{ value: '', class: '' },
{ value: '', class: '' },
{ value: '', class: '' },
];
$scope.changeEmail = function (email) {
if ($checkInput.checkEmail(email)) {
// email input is good
email.class = 'form-control-success'; // change from error to success
} else {
// email input is bad
if (email.class === 'form-control-success') {
email.class = 'form-control-error'; // change from success to error
}
}
};
If appropriate, you could use something like ng-repeat to avoid copy/paste in the HTML.
Even though Sunil D. pointed me basically to the answer the code is incorrect. Down below is the code that makes it work. http://codepen.io/basickarl/pen/MyoZNB
HTML:
<div ng-app="app" ng-controller="ctrl">
<form name="myForm">
<input ng-model="name" name="name">
<input ng-model="email" name="email" check-email>
</form>
</div>
CSS:
input {
border: 5px;
border-style: solid;
border-color: silver;
}
.input-invalid {
border-color: red;
}
.input-valid {
border-color: lime;
}
JS:
var app = angular.module('app', []);
app.controller('ctrl', ['$scope', function($scope) {
$scope.name = "";
$scope.email = "";
}]);
app.directive('checkEmail', [function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, el, attr, ctrl) {
ctrl.$validators.checkEmail = function(modelVal, viewVal) {
var regex = /^[^\s#]+#[^\s#]+\.[^\s#]+$/;
var isValid = regex.test(viewVal);
el.toggleClass('input-valid', isValid);
el.toggleClass('input-invalid', !isValid);
return isValid;
}
}
}
}]);
I have a simple html form containing regular text input. ng-minlength, ng-maxlength and ng-pattern angular built-in form input directives are set on the input.
Problem: ng-pattern check is applied before the length check by ng-minlength and ng-maxlength.
Question: how can I change the default check order: i.e. first check for the length, then apply pattern check?
Example:
<body ng-app>
<div>
<form name="myForm">
Name: <input name="name" type="text" ng-model="name" ng-minlength="3" ng-maxlength="16" ng-pattern="/^\w+$/"/>
<div ng-show="myForm.name.$dirty && myForm.name.$invalid">
<span ng-show="myForm.name.$error.pattern">Pattern error</span>
<span ng-show="myForm.name.$error.minlength || myForm.name.$error.maxlength">Length error</span>
</div>
<br/>
<input type="submit" value="Submit">
</form>
</div>
</body>
Current behavior:
enter "#" - see "Pattern error"
enter "###" - see "Pattern error"
Desired behavior:
enter "#" - see "Length error"
enter "###" - see "Pattern error"
FYI, related jsfiddle.
Thanks in advance.
Write your own directive:
var mod = angular.module("myApp", []);
mod.directive("nameValidation", function () {
return {
restrict: "A",
require: "ngModel",
link: function (scope, element, attrs, ngModelCtrl) {
var validate = function (value) {
var minLen = parseInt(attrs.myMinlength, 10),
maxLen = parseInt(attrs.myMaxlength, 10),
pattern = attrs.myPattern,
match = pattern.match(/^\/(.*)\/([gim]*)$/),
lenErr = false;
if (match) {
pattern = new RegExp(match[1], match[2]);
}
if (!ngModelCtrl.$isEmpty(value)) {
ngModelCtrl.$setValidity("pattern", true);
if ((minLen && value.length < minLen) || (maxLen && value.length > maxLen)) {
ngModelCtrl.$setValidity("length", false);
lenErr = true;
}
else {
ngModelCtrl.$setValidity("length", true);
lenErr = false;
}
if (!lenErr) {
if (match && !pattern.test(value)) {
ngModelCtrl.$setValidity("pattern", false);
}
else {
ngModelCtrl.$setValidity("pattern", true);
}
}
}
else {
ngModelCtrl.$setValidity("length", true);
ngModelCtrl.$setValidity("pattern", true);
}
}
ngModelCtrl.$parsers.push(validate);
ngModelCtrl.$formatters.push(validate);
}
}
});
Then in your HTML, include the app and use the directive:
<body ng-app="myApp">
<div>
<form name="myForm">
Name: <input name="name" type="text" ng-model="name" name-validation="" my-minlength="3" my-maxlength="16" my-pattern="/^\w+$/"/>
<div ng-show="myForm.name.$dirty && myForm.name.$invalid">
<span ng-show="myForm.name.$error.pattern">Pattern error</span>
<span ng-show="myForm.name.$error.length">Length error</span>
</div>
<br/>
<input type="submit" value="Submit">
</form>
</div>
</body>
The directive uses my-minlength, my-maxlength, and my-pattern for the three values. If length fails, that will trip first. If not, then pattern will show as error if it doesn't match. Consider renaming this directive if you want to use it other places besides name as minlength, maxlength, and pattern can be passed to it via attributes. If they are left off, they will be ignored.
See jsfiddle: http://jsfiddle.net/4zpxk/6/
I searched in angular code why this behavior. Then in the function 'textInputType' that it's the specific function that handles text inputs for the angular 'input' directive I found this at the end of this function, where we can see three blocks of code.
// pattern validator
if (pattern){
//validator logic
}
// min length validator
if (attr.ngMinlength) {
//validator logic
}
// max length validator
if (attr.ngMaxlength) {
//validator logic
}
So, no matter if you change the declaration order of your ng-* attributes in the html input element you will always get same result but if you change the order of the blocks, I mean, put the min length validator block before pattern validator block you will have the result that you expect.
This is a solution for your problem but you have to make a litte change in angular code and I don't know if you really like this. But you got a very common situation where order of the declaration of validation concepts matters, so, something more must be done to handle this. Thanks
You cannot change the default check order unfortunately.
One solution is to write a custom validator, not that difficult. Based on this answer, I came up with this code (fiddle)
Usage: There is an array of validation functions in the scope, they get passed to our custom directive "validators" as:
<input name="name" type="text" ng-model="name" validators="nameValidators"/>
A validator function would look like (e.g. for the minlength constraint):
function minlength(value, ngModel) {
if( value == null || value == "" || value.length >= 3 ) {
ngModel.$setValidity('minlength', true);
return value;
}
else {
ngModel.$setValidity('minlength', false);
return;
}
}
Important points are: it takes the value and the ngModel as arguments, performs the test (here value.length >= 3) and calls ngModel.$setValidity() as appropriate.
The directive registers the given functions with ngModel.$parsers:
app.directive("validators", function($parse) {
return {
restrict: "A",
require: "ngModel",
link: function(scope, el, attrs, ngModel) {
var getter = $parse(attrs.validators),
validators = getter(scope),
i;
for( i=0; i < validators.length; i++ ) {
ngModel.$parsers.push((function(index) {
return function(value) {
return validators[index](value, ngModel);
};
})(i));
}
}
};
});
Many details can be tweaked and improved, but the outline works (again link to fiddle). Now the order of validation is explicitly set by the order of the validator functions in the nameValidators array.
If you use ng-messages you should be able to set the order via the order of ng-message elements, e.g:
<div ng-messages="field.$error">
<ul class="validation-errors">
<li ng-message="required">This has the highest prio</li>
<li ng-message="min">Second in command</li>
<li ng-message="max">I'm last</li>
</ul>
</div>
Also the docs on this: https://docs.angularjs.org/api/ngMessages/directive/ngMessages
i just changed the order of your directives, pattern first
<input name="name" type="text" ng-model="name" ng-pattern="/^\w+$/" ng-minlength="3" ng-maxlength="16"/>
EDIT: uuum, tested your fiddel without changes and it shows your desired behavior ...
directives are compiled by priority, bbut i don't know how to set angulars directives priority ... sorry, should have tested this first