I am displaying a validation symbol in the left nav of a page to indicate whether the form is valid or not. When I load the page initially the form's $valid attribute is set to true, then eventually it changes to false (as it should be given the retrieved input data). The result is my validation symbol flickering from valid to invalid. Is there any way to prevent this? Currently the validation symbol is tied to a valid attribute on the $scope, which gets set within a watch. Is there any logic that could be added to the watch to check if the form hasn't finished initializing or validating? Thanks!
Here is my current watch code. The valid attribute goes from undefined to true to false after a couple different watch cycles.
$scope.$watch( 'sections.' + section.sectionName + '.sectionForm.$valid', function( valid ) {
section.valid = valid;
}, true);
And the HTML to display the validation symbol:
<span ng-class="{ 'fa fa-check': section.valid,
'fa fa-warning': !section.valid}">
</span>
I think the problem is the $watch function. The first time you will set "section.valid" as undefined. You don't need to watch manually. Each form directive creates an instance of FormController. So, you can check the form validity directly in view.
<span ng-class="{'fa fa-check': sectionFormName.$valid, 'fa fa-warning': sectionFormName.$invalid}"></span>
Related
I am struggling to figure out a way to trigger these AngularJS classes on a form I am trying to automatically fill with a chrome extension I am making. The form (specifically a textbox) has to be validated/modified before it will be validated and therefore submitted.
I originally tried using javascript to set the value of the textbox using the value property. This did not validate the form. I then tried using a dispatch event to send a key to the textbox, which resulted in nothing being input into the text box. How can I validate the form without requiring human input, or is this not possible?
Clarification, I am trying to replicate this action without user input by using a chrome extension.
Reference https://www.w3schools.com/angular/angular_validation.asp
Sounds like you need to create some events to simulate whatever angular is listening for, probably change or blur. Here's an example using click from mozilla:
https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events#Triggering_built-in_events
function simulateClick() {
var event = new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true
});
var cb = document.getElementById('checkbox');
var cancelled = !cb.dispatchEvent(event);
if (cancelled) {
// A handler called preventDefault.
alert("cancelled");
} else {
// None of the handlers called preventDefault.
alert("not cancelled");
}
}
How can I validate the form without requiring human input
Get the forms controls:
var controls = $scope.tdForm.$getControls();
Trigger their validators:
controls.forEach( _ => _.$validate() );
From the Docs:
$validate();
Runs each of the registered validators (first synchronous validators and then asynchronous validators). If the validity changes to invalid, the model will be set to undefined, unless ngModelOptions.allowInvalid is true. If the validity changes to valid, it will set the model to the last available valid $modelValue, i.e. either the last parsed value or the last value set from the scope.
For more information, see
AngularJS Form Controller API Reference
AngularJS ngModelController API Reference
When you type into the form, it updates the state of its controls (touched, dirty, etc.). According to how you define your fields validators (required, minLength...) the form will be valid or not after the user input.
In your submit method you should not proceed if any form fields are not valid. See AngularJS Developer Guide — Forms or Scotch Tutorials — AngularJS Form Validation you can have more details about AngularJS validation.
As Mike mentioned, you can use ngClass conditionally (see below) to apply some style classes only if a boolean condition occurr, for example the form is not valid.
<div ng-controller="ExampleController">
<form name="form" novalidate class="css-form">
<input type="text" ng-model="user.name" name="username" ng-class="{ 'error': !isValid }"/>
<div ng-show="form.$submitted>
<span ng-show="form.username.$error">Wrong Name</span></span>
</div>
<button ng-click="submit(user)"> Submit </button>
</form>
</div>
angular.module('formExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.isValid = true;
$scope.submit= function(user) {
if (user.name != 'Carl') {
$scope.isValid = false;
}
};
}]);
You can always programmatically change the form states if needed. For example to set the field to pristine:
$scope.form.$setPristine();
$scope.form.$setUntouched();
$setPristine sets the form's $pristine state to true, the $dirty state to false, removes the ng-dirty class and adds the ng-pristine class.
Additionally, it sets the $submitted state to false. This method will also propagate to all the controls contained in this form.
$setUntouched sets the form to its untouched state. This method can be called to remove the 'ng-touched' class and set the form controls to their untouched state (ng-untouched class).
Setting a form controls back to their untouched state is often useful when setting the form back to its pristine state.
UPDATE
Now it is clear what you are attempting to achieve. The two methods above can be used to set the form state, but if you want to validate it from code (this can be done passing the form to a service or directly in the controller for instance) then $validate() method will allow you to achieve that as mentioned by George.
I have a form where e-mail is optional. To control that there is a checkbox. If that checkbox is unchecked, the e-mail textbox would be disabled and therefore not posted on submit. However, on the next page, if I have code like as shown below, it gives me an error if the e-mail textbox is disabled.
if (isset($_POST['submit']))
{
$_SESSION["email"] = $_REQUEST['YourEMail'];
....
}
To get around that problem, I progammatically enable a disabled e-mail textbox just before submitting besides setting its value to an empty string. The code for that is shown below.
document.getElementById('YourEMail').disabled = false
document.getElementById('YourEMail').value = ''
However, one annoying problem remains, which is that, if the user goes back to the original page, the e-mail textbox is enabled, since I enabled it problematically just before submitting the form. However, I want it to be disabled in that case. How, can I achieve that? Alternatively, how in the next page, I could see that e-mail box was disabled and therefore not even try to read $_REQUEST['YourEmail']?
if the field "#YourEMail" is optional you can check if exists in PHP. There is no need for enable/disable the field using JS.
if (isset($_POST['submit']))
{
if (isset($_REQUEST['YourEMail']) && !empty($_REQUEST['YourEMail'])){
$_SESSION["email"] = $_REQUEST['YourEMail'];
}
}
You can test it like this using a ternary:
(isset($_REQUEST['YourEMail']) && !empty($_REQUEST['YourEMail'])) ? $_SESSION["email"] = $_REQUEST['YourEMail'] : FALSE;
This would only set the session variable if the request variable is set.
I am using Knockout to validate my page, and everything is working correctly. On input blur, if the required field is empty, the error symbol * is displayed next to the text box. However, I have a span tag at the bottom of the page that I want to display * Required field if and only if a field has the * next to it.
My intention was to have the span similar to
<span data-bind="visible: errors().length > 0"> * Required field </span>
The issue is, apparently on page load, the .length of my errors variable from
errors = ko.validation.group({ variables })
evaluates to all my inputs as having errors since they are null or empty on page load. Is there any way to disable this initial validation, but still have it validate on blur? Request any code if necessary, but I did not see that as pertinent at the moment.
errors() contains all the error messages of your validation group.
Try this:
showRequiredMessage = function() {
for (i = 0; i < errors().length; i++) {
if (errors()[i].indexOf("*") > -1 ) {
return true;
}
}
return false;
}
It checks if any of the error messages contain the *.
<span data-bind="visible: showRequiredMessage()"> * Required field </span>
This is javascript only solution. You can use jQuery too if you prefer.
Edit.
Are you creating the span elements for your validation messages? If so,
Try letting the ko-validation do that for you. Example:
var koValidationOptions = {
decorateInputElement: true,
errorElementClass: 'input-error',
insertMessages: true,
errorMessageClass: 'field-error'
};
ko.applyBindingsWithValidation(model, document.getElementById("form1"), koValidationOptions);
Otherwise, if you prefer to add the span manually, you can also test if the user has 'touched' the inputs:
visible: yourProperty.isModified() && !yourProperty.isValid()
Hope it helps
I have the following simple form with an type='email' input bound to a model:
<div ng-app>
<h2>Clearing ng-model</h2>
<div ng-controller="EmailCtrl">
<form name="emailForm" ng-submit="addEmail()">
<input type="email" name="email" ng-model="userEmail" placeholder="email#domain.com">
<span ng-show="emailForm.email.$invalid && emailForm.email.$dirty">invalid email</span>
<span ng-show="emailForm.$invalid">form invalid!</span>
</form>
<br/>
<button ng-click="clearViaUndefined()">clear via undefined</button>
<button ng-click="clearViaNull()">clear via null</button>
<button ng-click="clearViaEmptyString()">clear via empty string</button>
</div>
</div>
Suppose the user enters an invalid email but then clicks a 'Cancel' button...so the form needs to be reset.
In the ng-click handler for the 'Cancel' button, if I set the value of the model to 'undefined' this does not change the input element's $valid property back to true (nor the form's for that matter).
function EmailCtrl($scope) {
$scope.clearViaUndefined = function () {
$scope.userEmail = undefined;
};
$scope.clearViaNull = function () {
$scope.userEmail = null;
};
$scope.clearViaEmptyString = function () {
$scope.userEmail = "";
};
}
If I set the value of the model to an empty string "" or to null, then the $valid property does get set back to true.
Why is this?
I have a JS Fiddle here demonstrating the behaviour:
http://jsfiddle.net/U3pVM/12830/
Whenever you use ng-model on an input or select tag, angular internally manages two values for the field, one is $viewValue and other is $modelValue
$viewValue -> Used for display purpose on view
$modelValue-> Actual value which is used inside scope.
When using an input tag with type='email' Angular constantly validates the input value.
And if the value does not validate as a correct email, angular internally will set $modelValue to undefined and will set the form.fieldName.$error.fieldName attribute to true. So that field becomes invalid.
If you check the value of form.fieldName.$modelValue inside the controller you will find it as undefined.
So setting the model to 'undefined' in the controller, when the field is already invalid, changes nothing.
But if you set it to null or "" it will work as $modelValue and $viewValue both get changed - making the field valid again.
Hope this has cleared your understanding. Thanks.
Add ng-model-options="{allowInvalid: true}" on input field
then try setting ng-model to undefined hopefully will make the form/input valid again
see: https://docs.angularjs.org/api/ng/directive/ngModelOptions
I am stuck with certain scenarios in a validation. I need to valiadte a field - "First Name". Validations logic i have been using is -
If the field is dirty then validate against regex
ng-show="aspnetForm.FirstName.$dirty && aspnetForm.FirstName.$error.nameValidate"
If the field is marked required (currently keeping the field required is entirely business dependent so i am reading the true/false value from a JSON) then user may try submitting the form as it is
ng-show="blankSubmit && aspnetForm.FirstName.$error.required"
where blankSubmit is just a scope variable i am setting true on submit button click.
Now 3rd scenario is the logic i am not getting that is if the user clicks on the firstname text box and then without dirtying it, just blurs out, then the validation message should be displayed if ng-required is set true.If i just place ng-show="aspnetForm.FirstName.$error.required" then on the page load itself the error message is displayed which i dont want as it gives user a bad UX.
I solely want error message to be displayed when the attribute ng-required is set true and user blurs out of the textbox.
One possible solution is to create a directive which marks a field as visited which you can then check in the ng-show:
.directive('visited', function() {
return{
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModel){
element.bind('blur', function(){
scope.$apply(function() {
ngModel.visited = true;
});
});
}
};
});
View:
ng-show='form.field.$error.required && (form.field.$dirty || form.field.visited)'
I would suggest you using ng-messages. Your HTML would look like this:
<div ng-messages="aspnetForm.FirstName.$error" role="alert">
<div ng-message="required">Please enter a value for this field.</div>
<div ng-message="nameValidate">This field must be a valid.</div>
...
</div>
In case you want to use required depending on some variables I would suggest you using this <input ... required={{shouldBeRequired}}/>. This should work, required field should be validated only when proper value is set to it.