type="number" use only CustomValidator - parsley.js

How to I remove the builtIn "Integer" Validator from a html5 number field, but still use my CustomValidator?
My field:
<input id="temp" name="temp" type="number" data-parsley-trigger="change" data-parsley-number_international="" class="form-control">
My Custom Code:
window.ParsleyValidator
.addValidator('number_international',
function (value, requirement) {
if (format == '1'){
var reg = /^\d+(,\d+)*$/;
} else {
var reg = /^\d+(.\d+)*$/;
}
var res = reg.test(value);
return res;
}, 32)
.addMessage('en', 'number_international', 'Only numbers allowed!')
.addMessage('de', 'number_international', 'Nur Zahlen und Komma erlaubt!');
Thanks
Hannes!

Went back from "number" field type to "text" field type because I had serveral issues how "number" handles the comma separator. I let the user choose if he wants "," or "." as comma but it looks like I cannot change what Chrome or Firefox automatically expects.
Cheers
Hannes

Related

AngularJS md-autocomplete return all possible substrings

I'm using md-autocomplete to let users search through subjects at my university.
The problem is my search function only searches sequentially (left to right) through each display value.
For example: If I search "Arts and Architecture" I get "no results found", which I do not want to happen.
I would like "Arts and Architecture" to return a result.
The subjects are in this format:
$scope.subjects = [
{
value: 'AA',
display: 'AA - Arts and Architecture'
},
{
value: 'AAAS',
display: 'AAAS - African/Afr Amer Studies'
},
{
value: 'ABA',
display: 'ABA - Applied Behavior Analysis'
},
{
value: 'ABE',
display: 'ABE - Ag and Biological Engineering'
}
]
Here is my search method:
$scope.searchQuery = function(text) {
text = text.toUpperCase();
var result = $scope.subjects.filter(function(item) {
return item.display.includes(text);
});
return result;
}
Here is my html:
<md-autocomplete
md-selected-item="selectedItem"
md-search-text="searchText"
md-items="item in searchQuery(searchText)"
md-item-text="item.display"
md-min-length="0"
placeholder="Select a subject">
<md-item-template>
<span md-highlight-text="searchText">{{item.display}}</span>
</md-item-template>
<md-not-found>
No matches found.
</md-not-found>
</md-autocomplete>
Problem
This is due to case sensitivity, i.e. you're actually doing the equivalent of...
"Arts and Architecture".includes("ARTS AND ARCHITECTURE"); // false
...and because includes is case sensitive, it returns false. It just so happened to work at the beginning of your string because all of the letters are uppercase and the input too was uppercase:
"AA".includes("AA"); // true (fluke!)
Solution
If you make item.display and text both uppercase it should work:
$scope.searchQuery = function(text) {
var result = $scope.subjects.filter(function(item) {
return item.display.toUpperCase().includes(text.toUpperCase());
});
return result;
}
As per documentation JS method str.includes(searchString[, position]) states:
Params: position -> Optional. The position within the string at which to begin searching
for searchString.(defaults to 0).
so your code is starting from index 0.
How about using indexOf instead ? changing this line: return item.display.includes(text);
to return item.display.indexOf(text) !== -1;
"includes" function checks only if searched string exists in target string or not. For md-autocomplete to work, you need to match those objects from the array which contains your searched text or part of searched text. Modify your code to:
$scope.searchQuery = function(text) {
var result = $scope.subjects.filter(function(item) {
if (item.display.toUpperCase().indexOf(text.toUpperCase()) >-1)
return item;
});
return result;
}

Validate formly angularjs fields are not the same

I have dynamically added fields on click.
addNewFiled() {
let parent = this;
this.scope.fields.push({
key: 'field-'+parent.scope.fields.length,
type: 'horizontalInput',
templateOptions: {
placeholder :'Enter Field',
label: 'Filed',
required: false
},
validators: {
fieldFormat: function($viewValue, $modelValue, scope) {
let value = $viewValue;
if(value.length != 12){
scope.to.message = "Field should be 12 characters";
return false;
}
return true;
}
}
});
}
What I need is to validate the the value entered is not in another field in the validator, I tried looping through the model but its not efficient, any help is appreciated.
I have encountered this case once, I solved the issue using 2 maps
Basically, you will have 2 maps, one which will contain the index of the field mapped to the value of it, the second map will contain the value of the field mapped to the number of the repetitions of that value
In your validator, you decrement the number of repetitions for the previous value ( after done with other validations) and increase the number of repetitions of the new value and check if it's more than 1 then it's repeated.
In your Dialog define the two maps
private valuesMap: any = [];
private keysArray:any = [];
In your field, you inject a controller to save the index of the current field
controller: function ($scope) {
$scope.index = parent.scope.fields.length-1;
parent.keysArray[$scope.index] = $scope.index;
},
then in your validator
if(value) {
if(angular.isDefined(parent.valuesMap[parent.keysArray[scope.index]])) {
parent.valuesMap[parent.keysArray[scope.index]]= parent.valuesMap[parent.keysArray[scope.index]] -1;
}
parent.keysArray[scope.index] = value;
if(angular.isDefined(parent.valuesMap[value]) && parent.valuesMap[value] > 0) {
parent.valuesMap[value] = parent.valuesMap[value]+1;
scope.to.message = "Value is already entered";
return false;
}
parent.valuesMap[value] = 1;
}
Hope this works with your scenario
You don't need a validator on this, there is already default validation for field length through the minlength and maxlength properties in the templateOptions.
Simply do this:
templateOptions: {
placeholder :'Enter Field',
label: 'Filed',
required: false,
minlength: 12,
maxlength: 12
},

preventing maxLength on a input type number

I took me a while to figure this one out, but can someone post a cleaner method for limiting the number of digits in an input type='number'. One of the issues is that errors are thrown if $scope.variable = null....meaning nothing in the input field.
<input type="number" model='modalName' ng-change="monitorLength('modalName',16)">
JS:
$scope.monitorLength = function (model,maxLength) {
if ($scope[model] != null) { // prevent error on empty input field
var len = $scope[model].toString() ; // convert to a string
if (len.length > maxLength) { //evaluate string length
$scope[model] = parseInt(len.substring(0, maxLength));
// convert back to number or warning is thrown on input value not being a number
}
}
}
I then needed to expand up on this to account for number only, preventing any non-digit characters include '.' and ',' symbols:
var reg = new RegExp(/^\d+$/) ;
$scope.monitorLength = function (modal,maxLength) {
if ($scope[modal] != null) {
var len = $scope[modal].toString() ;
if (len.length > maxLength) {
$scope[modal] = parseInt(len.substring(0, maxLength));
} else if (!reg.test(len)) {
$scope[modal] = parseInt(len.substring(0, len.length-2));
}
}
}
Is there way to extract the ng-modal that was responsible for calling the ng-change? so the call would only have to be: ng-change="monitorLength(10)". And then in the function somehow dynamically retrieve the calling ng-modal?
<input type="number" max="99" onkeypress="if (this.value.length >= 2) return false;"/>
OR
<!--maxlength="10"-->
<input type="number" onKeyPress="if(this.value.length==10) return false;" />
this is a cleaner method for limiting the number, using ngMaxlength for that:
<input type="number" model='modalName' ng-maxlength="16">
You can find more attributes and info here
Is there way to extract the ng-modal that was responsible for calling the ng-change?
Yes. You can define a directive and require the ngModelController.
.directive('maxNum', function(){
return {
require: '^ngModel',
link: function($scope, elem, attrs){
// here you can add formatters/parsers to the ngModel
// to affect the change on the ngModel.$viewValue.
}
}
})
As #rolinger stated on the other answer, using the built in directives will not prevent the use from entering non-valid characters, they simply mark the model as being invalid.

Apply Range Validation for Input Value AngularJS

When an user entering a value, system should check whether this value is within the range of Minimum and Maximum defined for this field. also, need check for number of decimal points allowed.
<input ng-model='data.value1' >
<input ng-model='data.value2' >
<input ng-model='data.value3' >
<input ng-model='data.value4' >
you can add type="number". and for angularJS
<input type="number"
ng-model=""
[name=""]
[min=""]
[max=""]
[required=""]
[ng-required=""]
[ng-minlength=""]
[ng-maxlength=""]
[pattern=""]
[ng-pattern=""]
[ng-change=""]>
Follow the link for more clarification
AngularJs Documentation
Extending My comment:
var range = 'your range';
var checkRange = function () {
var value = data.value;
if(value <=range) {
//your code;
} else {
//your code;
}
}
Update:
$scope.data.value = 500;
$scope.$watch('data.value', function (oldVal,newVal) {
if(newVal > 1000 ) {
$scope.data.value = 500;
}
})

Need to require only one of a group of fields with Parsley

I am using Parsley.js for validating a form submission on a project. One of my needs is to have Parsley require that at least one of three fields have data in them, and only fail validation if none of the three fields has data.
I am not sure from the documentation, how to accomplish this. I already have Parsley validation working on the rest of the form.
You can do that with a custom validator like so
var CheckReccursion = 0;
window.Parsley.addValidator('min3', {
validateString: function (value, requirement, instance) {
var notice =$('#notice').html(' ');
var group = $(requirement);//a class
var FieldsEmpty = 0;
var FieldsNotEmpty = 0;
var count = 0
group.each(function () {
var _val = $(this).val()
var length = _val.length
if (length > 0) {
FieldsNotEmpty++;
}
else {
FieldsEmpty++;
}
count++;
})
var isValid = (FieldsNotEmpty >=1)
//recursively execute
group.each(function (index) {
if (CheckReccursion === index) {
CheckReccursion++;
$(this).parsley().validate();
CheckReccursion = 0;
}
})
return isValid;
}
});
$(function () {
var ok=false;
var notice =$('#notice');
$('#form1').parsley().on('form:validated', function(formInstance) {
ok = formInstance.isValid({force: true});
})
.on('form:submit', function() {
if(!ok){
notice.html('Please fill at least 1 field');
return false;
}
else{
notice.html('okay');
return false;//change to true to submit form here
}
});
});
then add parsley attributes to the group of fields like so:
<form id="form1" data-parsley-validate="true">
<input type="text" name="field1"
data-parsley-min3 = ".group1"
data-parsley-min3-message = "At least 1 must be filled"
class="group1">
<input type="text" name="field2"
data-parsley-min3 = ".group1"
data-parsley-min3-message = "At least 1 must be filled"
class="group1">
<input type="text" name="field3"
data-parsley-min3 = ".group1"
data-parsley-min3-message = "At least 1 must be filled"
class="group1">
<span id="notice"></span>
<input type="submit" value="Submit">
</form>
Check out this fiddle https://jsfiddle.net/xcoL5Lur/6/
My advice is to add hidden checkbox element with the attribute:
data-parsley-mincheck="1"
now just add javascript code that checks the hidden checkbox attribute when your form input has value (and the opposite).
notice that you will need to add extra attribute to your hidden checkbox:
data-parsley-error-message="Please fill at least one input"
Another approach is to using data-parsley-group and the isValid({group,force}) method.
<input type="text" name="input1" data-parsley-group="group1">
<input type="text" name="input2" data-parsley-group="group2">
<input type="text" name="input3" data-parsley-group="group3">
$('#myform').parsley().on('form:validate', function (formInstance) {
if(formInstance.isValid({group: 'group1', force: true}) ||
formInstance.isValid({group: 'group2', force: true}) ||
formInstance.isValid({group: 'group3', force: true})) {
//do nothing
}
else {
$('#errorContainer').html('You must correctly fill at least one of these three groups!');
formInstance.validationResult = false;
}
});
you can add as many as parsley's attributes as you wish, like data-parsley-type="email" that will be validated when the given input is not empty.
we set the force: true because it it forces validation even on non-required.fields.
the html render for the errorContainer is needed because the isValid method does not affect UI nor fires events.

Resources