Force an error on a field with Parsley.js - parsley.js

I'm using parsley (1.x) for the client-side validation of a form. I need to force an error on a certain field after the server-side validation.
<form>
<input type="text" name="field1" >
<input type="text" name="field2" >
<input type="submit" value="Send">
</form>
I've tried the methods described in this page but it doesn't work:
https://github.com/guillaumepotier/Parsley.js/issues/111
Anyone can help me?
Thx

In version 2.4.3 you can do this:
$('#fieldName').parsley().addError('forcederror', {message: 'My error message.', updateClass: true});
Source: http://parsleyjs.org/doc/index.html#psly-ui-for-javascript

I've managed to resolve this issue writing a new validation rule that return alwais an invalid field.
forcevalidation : function() {
return {
validate : function(val, elem, self) {
return false;
},
priority : 32
};
},
When I receive the ajax response I add the validator to the affected field and then I remove it:
affectedInput.attr('parsley-forcevalidation', true);
affectedInput.attr('parsley-error-message', errorMessage);
affectedInput.parsley('destroy');
affectedInput.parsley('validate');
affectedInput.removeAttr('parsley-forcevalidation');

Related

Angular: force custom form validator to run on any field input

I've written a custom validator for a password field, in order to verify the following scenarios:
if user has id defined, then password is always valid (can be empty, meaning no change)
if user does not have id defined, then password must not be empty (new users must have a password)
Problem is, I have noticed the validator is run only when the user interacts with the field (unlike required which is run on any input apparently). This makes the form appear valid even if password empty for a new user. Once I interact with the password input, everything seems fine.
I have solved the business logic requirement through the poorly documented ngRequired directive, but I would really like to understand the issue regarding the custom validator in case I run into it again.
You can try ui-validate with your business here:
$scope.passwordValidation = {
length: '$value.length >= 5 || $value.length == 0'
};
$scope.password2Validation = {
same_passwords: 'userPassword.value==$value'
};
And then your HTML:
<input id="password" class="form-control" type="password" ng-model="userPassword.value"
name="password" ui-validate="passwordValidation"/>
<input id="password2" class="form-control" type="password" ng-model="userPassword.confirm"
name="password2" ui-validate="password2Validation" ui-validate-watch="'userPassword.value'"/>
Please note the ui-validate-watch to tell ui-validate to care about the other password field.
After giving up on this, I ran into the problem again and I could not find a workaround. Fortunatel, I found a solution:
When you make a custom validator you need to bind it to the model field, not the form field. This makes it validate correctly all the time (one can assume due to differences between $modelValue and $viewValue properties that are on the form field which fudges up things). Please see code below for reference:
<input type="password" class="form-control" id="confirmpass" name="confirmpass" placeholder="Repeat Password"
ng-model="controller.selectedUser.passwordRepeat"
compare-to="controller.selectedUser.password"/>
And custom validator:
angular.module("compareTo", []).directive("compareTo", function() {
return {
require: "ngModel",
scope: {
otherModelValue: "=compareTo"
},
link: function(scope, element, attributes, ngModel) {
ngModel.$validators.compareTo = function(modelValue) {
return modelValue == scope.otherModelValue;
};
scope.$watch("otherModelValue", function() {
ngModel.$validate();
});
}
};
);

How to manually change the $error values for input tags - Angularjs

I am submitting a form via the angular $http and I want to give an error if the user bypassed the angularjs validation. I want to use the same error tag as if they didn't bypass the validation, userForm.name.$invalid && !userForm.name.$pristine how can I manually set this value ?
HTML
<body>
<form ng-controller="UserController" ng-model="userForm" name="userForm" ng-submit="createUser()">
<legend>Create User</legend>
<label>Name</label>
<input type="text" id="name" name="name" ng-model="user.name" placeholder="User Name" required>
<!-- HERE IS WHERE THE ERROR SHOWS -->
<p ng-show="userForm.name.$invalid && !userForm.name.$pristine"
<button class="btn btn-primary">Register</button>
</form>
</body>
ANGULAR JS
$http({
method : 'POST',
url : '/create',
data : user,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded'
}
})
.success(function(data) {
// I want to do something like this
name.$invalid = true;
name.$pristine = false;
});
I want to do something like what is in the success function. Therefore it will show the error message.
If you have access to scope in http success callback, you can do this to set the validity or mark it as dirty.
scope.userForm.name.$setDirty();
OR
scope.userForm.name.$setValidity('serverError', false); // creating a new field in $error and makes form field invalid.
To set the validity or pristine values of the form, you must use the function provided by the form.FormController. You can set the form to pristine or dirty but you cannot set a form directly to valid to not. You must set a particular model to invalid which will trigger the form value to invalid which will trigger the form to be invalid (https://docs.angularjs.org/api/ng/type/form.FormController).
//UserController
//$scope.userName is your object which has it's own controller using Angular Forms.
app.controller("UserController", function($scope){
$http({
method : 'POST',
url : '/create',
data : user,
headers : {
'Content-Type' : 'application/x-www-form-urlencoded'
}
})
.success(function(data) {
// I want to do something like this
$scope.userForm.$setDirty(); //Sets $pristine to false; Alternatively, you could call $setPristine() to set $pristine to true
$scope.userForm.name.$setValidity("length",false); //In your case, the "length" validation is likely something different or will be generic. This enables you to have name fail validation based multiple rules (perhaps length and unique)
});
});
If you want to check a specific field for validity, you can use a custom directive:
app.directive('customValidation', function(dataService) {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ctrl) {
ctrl.$parsers.unshift(function(viewValue){
//first, assume the value is valid, until proven otherwise
ctrl.$setValidity('customValidation', true);
//check against the API
if(viewValue.length > 0 && !ctrl.$error.customValidation) {
dataService.checkValidity(viewValue).then(function(response){
//API logic here
var results = response.data;
if(results.isNotValid)
ctrl.$setValidity('customValidation', false);
}).catch(function(response){
//some error occurred
ctrl.$setValidity('customValidation', false);
});
}
});
}
};
});
To use it:
<input custom-validation ng-model-options="{updateOn: 'default blur', debounce: { 'default': 700, 'blur': 0 }}" />

Angular Error: Model is not of type `number`

In my application I am getting the error:
Angular Error: ngModel:numfmt Model is not of type number
HTML:
<input ng-model="price" type="number" name="price" placeholder="enter price" id="price" />
In my controller I tried putting this to stop the issue. But I didn't have any luck.
$scope.$watch('price', function (val, old) {
$scope.value = parseInt(val);
});
How can I catch or mitigate this issue?
If you need more details don't hesitate to ask
You should use stringToNumber directive to resolve this error. The number input directive <input type="number"> requires the model to be a number. To store the number as a string you should use stringToNumber directive which convert it into the format the input[number] directive expects. Check below snippet.
<input ng-model="price" string-to-number type="number" name="price" placeholder="enter price" id="price" />
And here's the directive (from here):
.directive('stringToNumber', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
ngModel.$parsers.push(function(value) {
return '' + value;
});
ngModel.$formatters.push(function(value) {
return parseFloat(value, 10);
});
}
};
});
<input .... />
I have found angular to be fussy about the input it accepts. I found out the hard way, spending some time debugging something I wrote, which I passed through the notepad++ XML formatter to lay things out beautifully, in order to verify there were no mismatched tags.
The formatter replaced
<script .....></script>
with a self closing tag
<script ...../>
and the XML style self closing tags that the formatter created in my HTML prevented angular from being able interpret my file correctly.
Certain tags like <BR>, <meta> and (I think) <input> don't need closing. I don't know if this is your problem, but I would certainly edit the file to remove your self closing input tag before investigating any further.
you can make a stringToNumber directive to parse string to number, the perfect example of this is shown at below link : https://docs.angularjs.org/error/ngModel/numfmt
this.variable = isNaN(defaultValue.value) ? defaultValue.value : parseInt(defaultValue.value);

how to show validation messages when form is submitted in angular js

I have form in which there are couple of text fields and an email field.
I want to validate all fields for required / mandatory validation. I want to validate email field for email format validation. I want to carry out validation only when I click on two buttons and show the validation messages at top of the page. I know that I can check for email and required validations on field and using ng-show and a flag I can show messages. However I want to check each field's value in a directive and then set the flag to true which will make the message appear.
Here is my HTML. this gets loaded why state provider in main page which also defines following template and a controller for it. so its just a view partial:
<form name="myForm">
<div ng-show="validationFailed">
<!-- here i want to display validation messages using cca.validationMsgs object -->
</div>
<input type="text" name="test" ng-model="cca.field1" require />
....
<input type="email" mg-model="cca.field2" />
<input type="button" name="mybutton" />
</form>
Now the controller defined in another JS file:
'use strict';
(function(){
angular.module('store', []);
app.controller("StoreController",function(){
var cca = this;
cca.validationMsgs = {};
cca.validationFailed = false; //this flag should decide whether validation messages should be displayed on html page or not.when its true they are shown.
...//other mapped fields
});
And here is unfinished directive which I want to define and write my logic. Logic will be something like this :
1) iterate all elements which have require set on them and check their
$validators object / $error.required object is set
2) if yes set validationFailed flag to true,add the validation message to validationMsgs object and break the loop.
3) check if email type field has $error.email object set and if yes
similarly set validationFailed flag to true and add corresponding message to the object. Not sure if I really need a directive for this. I would like to apply the directive inside a element.
app.directive("requireOnSubmit",function(){
var directiveDefinitionObject = {
restrict:'E',
//.... need to fill in
//I can use link funcion but not sure how to map
// validationMsgs and validationFailed objects in here.
};
return directiveDefinitionObject;
});
Without any code or use case to go after I'll just show you a generic way of validating input. I'm going to use a signup functionality as an example.
Create a service/factory which will carry out the validation and return a promise, if the validation fails it will reject the promise. If not, it will resolve it.
Important note: A promise can only be resolved once (to either be fulfilled or rejected), meaning that the first declaration of a resolve or reject will always "win", which means you can't override any resolve or reject. So in this example if a field is empty and a user's email is undefined, the error message will be All fields must be filled in and not Invalid email format.
auth.factory('validation', ['$q', function($q) {
return {
validateSignup: function(newUser) {
var q = $q.defer();
for (var info in newUser) {
if (newUser[info] === '') {
q.reject('All fields must be filled in');
}
}
if (newUser.email === undefined) {
q.reject('Invalid email format');
}
else if (newUser.password.length < 8) {
q.reject('The password is too short');
}
else if (newUser.password != newUser.confirmedPass) {
q.reject('The passwords do not match');
}
q.resolve(true);
return q.promise;
}
}
}]);
And then inject this into your controller
auth.controller('AuthCtrl', ['$scope', '$location', 'validation', function($scope, $location, validation) {
$scope.status = {
message: ''
}
// Make sure nothing is undefined or validation will throw error
$scope.newUser = {
email: '',
password: '',
confirmedPass: ''
}
$scope.register = function() {
// Validation message will be set to status.message
// This will also clear the message for each request
$scope.status = {
message: ''
}
validation.validateSignup($scope.newUser)
.catch(function(err) {
// The validation didn't go through,
// display the error to the user
$scope.status.message = err;
})
.then(function(status) {
// If validation goes through
if (status === true) {
// Do something
}
});
}
And in the HTML you can have something like this:
<form>
<div>
<label for="email">Email:</label>
<input type="email" id="email" ng-model="newUser.email">
</div>
<div>
<label for="password">Password:</label>
<input type="password" id="confirm-pass" ng-model="newUser.password">
</div>
<div>
<label for="confirm-pass">Confirm password:</label>
<input type="password" id="confirm-pass" ng-model="newUser.confirmedPass">
</div>
<div>
<div>
<span ng-bind="status.message"></span>
</div>
</div>
<div>
<button ng-click="register(newUser)">Register</button>
</div>
</form>
You can use this example and modify it for your use case.

AngularJS - Running a funcion on false of ng-pattern

I know that this issue has been mentioned before. Although I believe that this issue is slightly different.
Link
Link
I have the following code
<textarea name="Text2" cols="40" rows="2" ng-model="pageModel.storeText" ng-pattern="/^(?:\d+(?:, *|))*\d+$/" class="form-control"></textarea>
<span ng-show="itemStoreForm.Text2.$error.pattern">ERROR</span>
I need the ng-show in the span to initiate a function I have based in a controller:
$scope.storeError = function(){
messageService.setMessage("messageContainer", "Please enter store numbers in correct format", "danger");
};
How can I call the function storeError()?
If you can access the scope-object from your controller, try
$scope.$watch('itemStoreForm.Text2.$error', function(error) {
if (error && error.pattern) {
$scope.storeError();
}
});
Since the FormController is published on $scope via name, it should be accessible for a watch-function.

Resources