Dynamic pattern validation in Angular 2 and 4 - validation

Input validation works fine with a fixed pattern, e.g.
<input type="number"
[(ngModel)]="info.sortOrder"
pattern="[0-9][0-9]"
id="sortOrder" name="sortOrder" #sortOrder="ngModel"/>
When changing the pattern to be evaluated through a function, validation always fails. The function "customPattern()" is called, though.
<input type="number"
[(ngModel)]="info.sortOrder"
[pattern]="customPattern()"
id="sortOrder" name="sortOrder" #sortOrder="ngModel"/>
With
customPattern() { return "[1-9][0-9]"; }
Is this a bug or is this not supposed to work this way?

I guess you are dong wrong, #black
I would recommend you to use Reactive Forms approach to achieve the desire result.
create a reactive form.
Add the control name for eg('number_validation').
(optional) Register the HTML input element with the formControlName same as above ('number_validation').
create a field 'regex' = '[0-9][0-9]' in the component.ts file.
Bind the [pattern] = regex in the HTML HTML input element tag.
Listen the change and change the regex pattern according to the requirement.
In ts file.
someForm: FormGroup;
this.someForm= new FormGroup({
'some_name': new FormControl('', [
Validators.required])});
regex = /[0-9][0-9]/;
In HTML:
<input type="number"
[pattern]=regex
id="sortOrder"
formControlName=some_name
name="sortOrder"/>
Logic :
It depends on the requirement how you are going to change the regex value, dynamically.
eg.
ngAfterViewInit() {
this.someForm.get('some_name').valueChanges.subscribe(val => {
if (val === 'anything') {
this.regex = /change the regex/;
} else if (val === 'anything_other') {
this.regex = /change the regex/;
}
});
}
Hope it help you, or other devs! :)

In you component, simply define a member variable like this:
export class AppComponent {
customPattern = '[1-9][0-9]';
In your html, use interpolation like this:
pattern = "{{customPattern}}"
That should work.

Related

AlpineJS - autoselection doesn't work when there is more than one todo

I'm making a little todo app in AlpineJS and I'm running into a problem of autoselecting a field when a user clicks on a todo. This problem only happens when there are multiple todos.
When the user enters the first todo onto the app, they can then click on the todo to edit it. The field will autoselect as expected. However, when the user adds more than one todo onto the app and wants to edit the n+1 todo, the field will no longer autoselects, but the first todo still autoselects just fine.
Here's my CodePen for your reference.
Here's what my edit functionality looks like:
JS
[...]
edit(todo) {
todo.editing = !todo.editing
this.$nextTick(() => {
document.getElementById(`edit-${todo.id}`).select()
})
}
[...]
HTML
[...]
<div
x-text="todo.item"
class="todo-item"
#click="edit(todo)" // <-- point of interest
x-show="!todo.editing"
:class="{ 'completed' : todo.completed }"
>
</div>
<input
type="text"
x-show="todo.editing"
:value="todo.item"
x-model="todo.item"
#keydown.enter="edit(todo)"
#keydown.escape="todo.editing = false"
#click.away="todo.editing = false"
class="edit-input"
:id="`edit-${todo.id}`" // <-- point of interest
/>
[...]
Would anyone have an idea of what might be wrong with my logic? Thank you for the help!
It seems using setTimeout(() => { ... }, 1) (timeout of 1ms) works, see the following Codepen modified from yours.
There are known issues in Alpine.js around $nextTick.
I would also recommend using x-ref instead of ids, so your input would look as follows:
<input
type="text"
x-show="todo.editing"
:value="todo.item"
x-model="todo.item"
#keydown.enter="edit(todo)"
#keydown.escape="todo.editing = false"
#click.away="todo.editing = false"
class="edit-input"
:x-ref="`edit-${todo.id}`"
/>
You can then set edit(todo) to be:
edit(todo) {
todo.editing = !todo.editing
setTimeout(() => {
this.$refs[`edit-${todo.id}`].select()
}, 1)
}

VeeValidate multiple password constraints

I'm wondering if it's possible to have multiple password requirements passed to VeeValidate in order to display which requirements a user is missing.
For instance, if we require that a user's password should have at least one uppercase letter and at least one number and be at least 5 characters long, and the user types in "a1bb", we'd like to be able to display two error messages; one associated with the length requirement not being met and one related to the uppercase requirement not being met.
Ultimately, we'd like to be able to do something like this:
Would that be possible with VeeValidate? Or are there any examples of a similar approach?
VeeValidate allows you to display multiple errors fields but you need to disable the fastExist config option first:
VeeValidate only generates one message per field by default as it uses
a fast-exit strategy when running the validation pipeline. [...] To disable this behavior you may want to configure the
fastExit option in VeeValidate's config or use the continues modifier. (source)
For the rules you want to apply to password, you can use the existing min rule for the minimum length.
For the other rules (check upcase, lowercase, special char and digit), it's about regex check. VeeValidate actually provides a regex rule but in your case you need multiple ones.
So you need to define custom rules. I put some examples in the snippet below in the created hook but you also can define them globally.
In my example, I create a method to return a css class error by checking the errors by rule name.(source)
Now the style is yours.
const config = {
fastExit: false
}
Vue.use(VeeValidate, config)
new Vue({
el: "#app",
data() {
return { password: '' }
},
created() {
this.$validator.extend('upCase', {
getMessage: () => "One uppercase character",
validate: value => value.match(/[A-Z]/g) !== null
})
this.$validator.extend('number', {
getMessage: () => "One number",
validate: value => value.match(/[0-9]/g) !== null
})
},
methods: {
errorClass(rule) {
return {
'error': this.errors.firstByRule('password', rule)
}
}
}
})
li {
color: #B1B1B1;
}
li.error {
color: #262626;
}
<script src="https://unpkg.com/vue#2.6.8/dist/vue.min.js"></script>
<script src="https://unpkg.com/vee-validate#2.0.0-rc.19/dist/vee-validate.js"></script>
<div id="app">
<input type="text" v-validate="'min:8|number|upCase'" name="password" >
<ul>
<li :class="errorClass('upCase')">One uppercase character</li>
<li :class="errorClass('number')">One number</li>
<li :class="errorClass('min')">8 characters minimum</li>
</ul>
</div>
check this solution
make a custom rule form VEEVALIDATE
STRONG PASSWORD VALIDATION
http://frankclark.xyz/veevalidate-strong-password-and-confirmation-validation

VueJS add class depending item v-for [duplicate]

I have some data that is accessible via:
{{ content['term_goes_here'] }}
... and this evaluated to either true or false. I'd like to add a class depending on the truthiness of the expression like so:
<i class="fa" v-bind:class="[{{content['cravings']}} ? 'fa-checkbox-marked' : 'fa-checkbox-blank-outline']"></i>
where true gives me the class fa-checkbox-marked and false would give me fa-checkbox-blank-outline. The way I wrote it above gives me an error:
- invalid expression: v-bind:class="[{{content['cravings']}} ? 'fa-checkbox-marked' : 'fa-checkbox-blank-outline']"
How should I write it to be able to conditionally determine the class?
Use the object syntax.
v-bind:class="{'fa-checkbox-marked': content['cravings'], 'fa-checkbox-blank-outline': !content['cravings']}"
When the object gets more complicated, extract it into a method.
v-bind:class="getClass()"
methods:{
getClass(){
return {
'fa-checkbox-marked': this.content['cravings'],
'fa-checkbox-blank-outline': !this.content['cravings']}
}
}
Finally, you could make this work for any content property like this.
v-bind:class="getClass('cravings')"
methods:{
getClass(property){
return {
'fa-checkbox-marked': this.content[property],
'fa-checkbox-blank-outline': !this.content[property]
}
}
}
<i class="fa" v-bind:class="cravings"></i>
and add in computed :
computed: {
cravings: function() {
return this.content['cravings'] ? 'fa-checkbox-marked' : 'fa-checkbox-blank-outline';
}
}
Why not pass an object to v-bind:class to dynamically toggle the class:
<div v-bind:class="{ disabled: order.cancelled_at }"></div>
This is what is recommended by the Vue docs.
the problem is blade, try this
<i class="fa" v-bind:class="['{{content['cravings']}}' ? 'fa-checkbox-marked' : 'fa-checkbox-blank-outline']"></i>
You could use string template like with backticks `` :
:class="`${content['cravings'] ? 'fa-checkbox-marked' : 'fa-checkbox-blank-outline'}`"
if you want to apply separate css classes for same element with conditions in Vue.js
you can use the below given method.it worked in my scenario.
html
<div class="Main" v-bind:class="{ Sub: page}" >
in here, Main and Sub are two different class names for same div element.
v-bind:class directive is used to bind the sub class in here.
page is the property we use to update the classes when it's value changed.
js
data:{
page : true;
}
here we can apply a condition if we needed.
so, if the page property becomes true element will go with Main and Sub claases css styles. but if false only Main class css styles will be applied.

AngularJS: Is there any way to determine which fields are making a form invalid?

I have the following code in an AngularJS application, inside of a controller,
which is called from an ng-submit function, which belongs to a form with name profileForm:
$scope.updateProfile = function() {
if($scope.profileForm.$invalid) {
//error handling..
}
//etc.
};
Inside of this function, is there any way to figure out which fields are causing the entire form to be called invalid?
Each input name's validation information is exposed as property in form's name in scope.
HTML
<form name="someForm" action="/">
<input name="username" required />
<input name="password" type="password" required />
</form>
JS
$scope.someForm.username.$valid
// > false
$scope.someForm.password.$error
// > { required: true }
The exposed properties are $pristine, $dirty, $valid, $invalid, $error.
If you want to iterate over the errors for some reason:
$scope.someForm.$error
// > { required: [{$name: "username", $error: true /*...*/},
// {$name: "password", /*..*/}] }
Each rule in error will be exposed in $error.
Here is a plunkr to play with http://plnkr.co/edit/zCircDauLfeMcMUSnYaO?p=preview
For checking which field of form is invalid
console.log($scope.FORM_NAME.$error.required);
this will output the array of invalid fields of the form
If you want to see which fields are messing up with your validation and you have jQuery to help you, just search for the "ng-invalid" class on the javascript console.
$('.ng-invalid');
It will list all DOM elements which failed validation for any reason.
You can loop through form.$error.pattern.
$scope.updateProfile = function() {
var error = $scope.profileForm.$error;
angular.forEach(error.pattern, function(field){
if(field.$invalid){
var fieldName = field.$name;
....
}
});
}
I wanted to display all the errors in the disabled Save button tooltip, so the user will know why is disable instead of scrolling up and down the long form.
Note: remember to add name property to the fields in your form
if (frm) {
disable = frm.$invalid;
if (frm.$invalid && frm.$error && frm.$error.required) {
frm.$error.required.forEach(function (error) {
disableArray.push(error.$name + ' is required');
});
}
}
if (disableArray.length > 0) {
vm.disableMessage = disableArray.toString();
}
For my application i display error like this:
<ul ng-repeat="errs in myForm.$error">
<li ng-repeat="err in errs">{{err.$name}}</li></ul>
if you want to see everything, just user 'err' that will display something like this:
"$validators": {},
"$asyncValidators": {},
"$parsers": [],
"$formatters": [],
"$viewChangeListeners": [],
"$untouched": true,
"$touched": false,
"$pristine": true,
"$dirty": false,
"$valid": false,
"$invalid": true,
"$error": { "required": true },
"$name": "errorfieldName",
"$options": {}
Not this well formatted, but you will see these things there...
When any field is invalid, if you try to get its value, it will be undefined.
Lets say you have a text input attached to $scope.mynum that is valid only when you type numbers, and you have typed ABC on it.
If you try to get the value of $scope.mynum, it would be undefined; it wouldn't return the ABC.
(Probably you know all this, but anyway)
So, I would use an array that have all the elements that need validation that I have added to the scope and use a filter (with underscore.js for example) to check which ones return as typeof undefined.
And those would be the fields causing the invalid state.
If you want to find field(s) which invalidates form on UI without programmatically, just right click inspect (open developer tools in elements view) then search for ng-invalid with ctrl+f inside this tab. Then for each field you find ng-invalid class for, you can check if field is not given any value while it is required, or other rules it may violate (invalid email format, out of range / max / min definition, etc.). This is the easiest way.

Codeigniter form validation allow numeric type to include comma

When validating prices with CI I use the following rule;
$this->form_validation->set_rules('price','lang:price','required|numeric|greater_than[0.99]');
Is there any way to allow commas in this rule line? Or do i have to create a callback?
Codeigniter 3 offers a regex validation. Form Validation
Using the regex given by Ben... No callback is required.
$this->form_validation->set_rules('price','lang:price','required|numeric|greater_than[0.99]|regex_match[/^[0-9,]+$/]');
From using the form validation library, I've never seen anything that would allow you to do that without a callback.
This would be the callback though:
function numeric_wcomma ($str)
{
return preg_match('/^[0-9,]+$/', $str);
}
with a rule of
$this->form_validation->set_rules('input', 'Input', 'callback_numeric_wcomma');
My answer is:
$this->form_validation->set_rules('price','lang:price','regex_match[/^(?!0*[.,]?0+$)\d*[.,]?\d+$/m]');
or do it in your codeigniter view. Add script:
<script>
function replace(element) {
// set temp value
var tmp = element.value;
// replace everything that's not a number or comma or decimal
tmp = tmp.replace(/[^0-9,.,-]/g, "");
// replace commas with decimal
tmp = tmp.replace(/,/, ".");
// set element value to new value
element.value = tmp;
}
</script>
and then use input like this:
<input id="something" onkeyup="replace(this)" type="text">

Resources