how to make an angular input not be required when it's not shown - angularjs

I have the following code
<div class="form-group" show-errors ng-show="contact.ContactType === 'LegallyMarriedSpouse' || contact.ContactType === 'Self'">
<label class="control-label">Social Security Number</label>
<input type="text" class="form-control" ng-model="contact.SSN" ui-mask="999-99-9999" name="SSN" maxlength="50" required />
</div>
I would have thought that Angular would have made sure that the hidden field was no longer required however that is not the case. although the user can't see it it's clearly still stopping the form from being submitted because I see the following error in the console.
An invalid form control with name='SSN' is not focusable.
So - the question is how do I handle this? If it's displayed I want it to be required if not obviously we can't try and force the user to fill out the values.

2 solutions:
use ng-if rather than ng-show to remove the input from the form rather than hiding it
instead of required, use ng-required="contact.ContactType === 'LegallyMarriedSpouse' || contact.ContactType === 'Self'" to make it required only when the condition showing the field is true. You should put that complex condition in a scope function though, to avoid duplicating it.
Note however that even if the form is invalid, it can still be submitted, unless you're explicitely preventing it by disabling its submit button when the form is invalid. I don't think the error you're seeing has anything to do with the form being invalid.
Also note that the second solution will only deal with the field being required. If the value inside the field is too long or doesn't match with the mask, the field will stay invalid. So you should probably use the first solution.

Related

How to keep form error message blank on initial load in AngularJS

I'm trying to learn forms in AngularJS 1.x. But I have error messages that are always on when it first loads. How to develop behaviour such that they are blank on load, and only red after a submit if fields were not entered? Seems to be a few states I have to use the built-in directives for.
All the elements are similar so let's just take apart this bit. Also if different for a radio and dropdown list maybe we can discuss that too.
<p>First Name:<input type="text" id="firstName" ng-model="firstName" required/>
<span style="background-color: red" ng-if="identification.firstName.$error.required">The first name is required.</span>
</p>
Do I chain a few directives with || or && ?
Behaviour I'm aiming for
How to keep the error messages off when it loads?
when I hit submit, and a field is blank, will it then activate the css red error messages?
I'd like the error messages to clear as I fill in the form without reloading.
Yeah, so any tips greatly appreciated. Doesn't have to be particularly pretty
Thanks
UPDATE 1
gist of current code
Well I took a stab at it. Still really a hot mess at this point. Don't know how to use submit to test for each field and then display the error message if blank. Also seems like a lot of duplication on the testing of field states. Is there a better way to break up that logic? Ugggghhhhh
UPDATE 2
This one's weird, the form now has all text boxes not buttons or checkboxes!? But the HTML hasn't changed. Sigh
ng-if="identification.firstName.$error.required && !$pristine"
Go search more on $pristine and $dirty validator
You can add some other property to your ng-if and set its value to true only when form is submitted.
in your html add this new property
<p>First Name:<input type="text" id="firstName" ng-model="firstName" required/>
<span style="background-color: red" ng-if="identification.firstName.$error.required && running">The first name is required.</span>
</p>
in your controller set this property to true when form is submitted
$scope.submit = function(){
$scope.running = true;
...
}

Clear ng-model then Update ng-model with new value

Angular and Ionic Application
I have a form that has a lot of <select> elements, The form offers the user to select from a list or if the <option> = 'Other' then I show another <input> to enter the value. I then save the value to another ng-model.
<select data-ng-model="minor.tests.liveEarth"
name="minorTestLiveEarth"
required>
<option></option>
<option>>200</option>
<option>>299</option>
<option>>500</option>
<option>>1000</option>
<option>Other</option>
</select>
</label>
<label class="item item-input item-stacked-label" ng-show="minor.tests.liveEarth === 'Other'">
<span class="input-label">Please Specify</span>
<input type="text"
placeholder="live earth other"
ng-maxlength="10"
data-ng-model="minor.tests.liveEarthOther"
name="minorTestLiveEarthOther">
</label>
I originally used <datalist> but doesn't show up on iOS.
I assigned the liveEarthOther to the same as the <select> liveEarth but it has 'Other' assigned to the ng-model, which then the user has to delete the input value Other before entering their value.
I have looked for a combobox kind of control but haven't found one that works properly.
How could I make this into a directive or any thing suitable that could perform the renaming without the user having to delete the value.
I want to use this functionality many times in the application I am building.
You may have overcomplicated things by re-using the ngModel. If you change the value minor.tests.liveEarth you'll mess up your select because anything other than the given values will cause nothing to be selected. But if you don't change minor.tests.liveEarth then you'll have to delete it when the user fills in the text input. This would then also mess up the select box!
What I would do is record the value of the text input to a different variable. Keep the ng-show="minor.tests.liveEarth === 'Other'" as it is, but change your input to
<input type="text"
placeholder="Fill in your other live earth"
ng-maxlength="10"
data-ng-model="tempVar" />
This way the input will be still be recorded, but the select won't be messed up on the ngModel change. Due to the placeholder, the user will know that they have to fill in the text box.
In your js, you'll have to create a validating function when the form is submitted along the lines of:
var validateLiveEarth = function(){
if(minor.tests.liveEarth === "Other"){
//check that tempVar meets validation
//assign tempVar to whatever form you're sending
}
}

AngularJS Form Validation - Bind input to model eventhough there is input error

I have a form using the built in angularjs form validation and ng-messages. Look at this code.
<div class="form-group" ng-class="{ 'has-error': form1.firstName.$invalid && form1.firstName.$touched }">
<label class="control-label">* First Name</label>
<input name="firstName" ng-model="applicant.firstName" required ng-pattern="alpha" ng-minlength="2" ng-maxlength="30" type="text" class="form-control" />
<div class="help-block has-error" ng-messages="form1.firstName.$error" ng-if="form1.firstName.$touched">
<div ng-messages-include src="/worktrustedV2/app/modules/core/templates/errorMessages.template.html"></div>
<div ng-message="pattern" class="error" style="color:red">This field requires letters only</div>
</div>
If the input doesnt trigger an error, then if you console.log($scope.applicant.firstName);, it prints the value, but if the input has an error, console.log($scope.applicant.firstName); becomes undefined.
Is there a way to make angular(or maybe it because of ng-messages) bind the input's value even if it has error? I want to make console.log($scope.applicant.firstname); to print the value even if the input has error.
EDIT: After you rephrased the question
I remember I was facing the same problem when writing an application; when you have 10000+ lines of code, you can imagine the situation. Now, if I understand it clearly, you WANT applicant.firstName to have SOME value even if the validation fails? If that's the case, let me explain to you how Angular works.
Whenever you define a field as an ng-model, the internals of Angular manage two values for this field:
$modelValue
$viewValue
As you might have guessed from the names of these variables, $modelValue is the value of the input instance to be used by the model, and the $viewValue is used for displaying it, etc. (AngularJS ngModel)
Our good friends at Angular have done something pretty useful: whenever the input field doesn't pass the test, the $modelValue is set to undefined. So, when you try to get the value of that model, Angular sees that it's empty and so returns an undefined. Also, when the validation fails, <parentForm>.$invalid is switched to true.
For your case, you can give it a default value; so, even if the validation fails, you'll get SOME value.
Simple add:
$scope.applicant.firstName = "example#gmail.com";
in the controller to get a value even after the validation fails.
Yeah! You can check if the value if undefined and break out of the function. That's the best method.
...
$scope.submit = function() {
if( $scope.firstName === undefined ||
$scope.firstName === null ) { return; }
... // Continue normal execution
}

ng-true-value and required in AngularJs

<input type="checkbox" id="acknowledge" name="acknowledge"
ng-model="formData.acknowledge"
ng-true-value="true"
ng-required="formData.acknowledge !='true'"/>
<div ng-show="(peopleworksForm.acknowledge.$dirty || peopleworksForm.submited) && formData.acknowledge !='true'">
Please acknowledge that the information is correct</div>
I feel that something is wrong here with ng-required. Without required or ng- required it works fine. It returns the error message if I don't check the checkbox. But there also a problem: although I check the checkbox, form.$valid = false. That's why I tried using required or ng-required. You may asked me to remove the ng-true-value and use required. I know that also working. But the problem is I load formData.acknowledge = "true" inside my controller, so when the page loads the checkbox has to be checked. So I had to use ng-true-value. Can any one help me?
To restate, you want to show a message when the checkbox acknowledge is not checked by checking the $valid state of the form or the checkbox.
Also, the checkbox should be checked from the controller when assigned "true" - string value, rather than true - boolean value.
You are correct that you need to use ng-true-value to redefine the value given to the model for a checked state. You are using ng-true-value incorrectly, however, because you are not assigning the string value, but rather the boolean.
The correct way is below (notice the double-quotes "' '"):
<input type="checkbox" name="foo"
ng-model="foo" ng-true-value="'true'" required>
In the controller you could assign to "true":
$scope.foo = "true";
plunker
Also, you don't need to use ng-required with an expression - this would make the control required on a conditional basis, and I think you want it to be always "required".
General Pattern
You should be getting any data bindings you need from your controller. If necessary, those pieces of data should come from a service you inject or depend on. It sounds like you're roughly following that.
ng-true-value
You should only need to use ng-true-value if you want something other than true or false, as that is the default behavior.
what's probably wrong
In your controller, you should probably just be defaulting your property to true if that's what you need.
informationAcknowledgeOnlineRegistrationChange = true; // replace value you get from your service
should do everything you need.
As you have answer yourself, you can remove the ng-true-value and use the required:
<input type="checkbox" id="acknowledge" name="acknowledge"
ng-model="formData.acknowledge"
required />
<div ng-show="(peopleworksForm.acknowledge.$dirty || peopleworksForm.submited) && formData.acknowledge">
Please acknowledge that the information is correct</div>
In the controller, the data binding would be:
formData.acknowledge = true; //not 'true' as string
when you don't check the check box no value is provided which goes against ng-required . here what you can do is to set a default value for for the check box when user doesn't provide any value for the checkbox

What is the difference between required and ng-required?

What is the difference between required and ng-required (form validation)?
AngularJS form elements look for the required attribute to perform validation functions. ng-required allows you to set the required attribute depending on a boolean test (for instance, only require field B - say, a student number - if the field A has a certain value - if you selected "student" as a choice)
As an example, <input required> and <input ng-required="true"> are essentially the same thing
If you are wondering why this is this way, (and not just make <input required="true"> or <input required="false">), it is due to the limitations of HTML - the required attribute has no associated value - its mere presence means (as per HTML standards) that the element is required - so angular needs a way to set/unset required value (required="false" would be invalid HTML)
I would like to make a addon for tiago's answer:
Suppose you're hiding element using ng-show and adding a required attribute on the same:
<div ng-show="false">
<input required name="something" ng-model="name"/>
</div>
will throw an error something like :
An invalid form control with name='' is not focusable
This is because you just cannot impose required validation on hidden elements. Using ng-required makes it easier to conditionally apply required validation which is just awesome!!
The HTML attribute required="required" is a statement telling the browser that this field is required in order for the form to be valid. (required="required" is the XHTML form, just using required is equivalent)
The Angular attribute ng-required="yourCondition" means 'isRequired(yourCondition)' and sets the HTML attribute dynamically for you depending on your condition.
Also note that the HTML version is confusing, it is not possible to write something conditional like required="true" or required="false", only the presence of the attribute matters (present means true) ! This is where Angular helps you out with ng-required.

Resources