Angular bootstrap conditionally-required fields - angularjs

This seems to be very common, yet the solutions for it seem complex.
I've got a section of my form that is optional. If enabled, then its fields are required.
<!-- begin optional section -->
<label>
<h4>Trailer </h4>
<span>( optional </span>
<input class="input-inline" ng-model="hasTrailer" type="checkbox"/>
<span>)</span>
<h4 style="display: inline"> :</h4>
</label>
<div class="form-group">
<label for="trailerNumber"> Number:</label>
<div>
<input
type="text"
name="trailerNumber"
ng-disabled="!hasTrailer"
ng-model="vm.Manifest.Trailer.number"
required />
</div>
<div>
<div
class="error-message"
ng-show="hasTrailer && form.trailerNumber.$invalid && form.trailerNumber.$touched || form.submitted">
<span> Trailer Number is required.</span >
</div>
</div>
</div>
<!-- end optional section -->
So, at the top of the section there is a checkbox, whose model is 'trailer'.
If checked, the fields are required.
What I really want is ideally:
<input type="text" required="hasTrailer">
or maybe
<input type="text" ng-attr({'required':hasTrailer})
i.e. if hasTrailer===true then required=true

You could use ng-required directive which will conditionally make input required when provided expression becomes true.
<input type="text" ng-required="hasTrailer">

You can achieve that by using ngRequired. You can read about it here
It is basically used like this in the html element
<input type="text" ng-required="hasTrailer">
hasTrailer should be a boolean property in the scope.

I was about to go with this option, which does the same thing, but additionally makes the whole section disappear.
<div ng-if="hasTrailer">
<!-- all my optional fields-->
</div>

Related

how to exclude one specific ng-form in angular

I have the following form structure, how can I validate this form except for last item in ng-repeat ? it is a kind of dynamic list of inputs and last input is an empty slot, and as the user types in the input, another empty input field is added to items collection and so on, how can I tell parentForm to ignore the last item?
<div ng-form="parentForm">
<div ng-repeat="item in items" ng-form="itemForm">
<input type="text" ng-model="item.name" required/>
</div>
<input type="submit" ng-disabled="parentForm.$invalid" />
</div>
I would use special ngRepeat property $last with combination with ngRequired:
<div ng-form="parentForm">
<div ng-repeat="item in items" ng-form="itemForm">
<input type="text" ng-model="item.name" ng-required="!$last" />
</div>
<input type="submit" ng-disabled="parentForm.$invalid" />
</div>

getting value from angular radio buttons

I am trying to follow the angular docs for radio buttons.
https://docs.angularjs.org/api/ng/input/input%5Bradio%5D
Don't know what I'm doing wrong.
Ultimately, I want the div "stuff" to have class "muted" if radio option 3 is selected.
my html:
<form name="shippingVm.MasterCartonForm" ng-controller="shippingControler as shippingVm" >
[{{shippingVm.shipOption.val}}]
<div class="col-sm-3 col-sm-offset-1">
<label class="radio-inline">
<input type="radio" ng-model="shippingVm.shipOption.val" name="shippingOptions" ng-value="one" />
I will call Purolator for a pickup.
</label>
</div>
<div class="col-sm-3">
<label class="radio-inline">
<input type="radio" ng-model="shippingVm.shipOption.val" name="shipOptions" ng-value="two" />
I will deliver them to Purolator.
</label>
</div>
<div class="col-sm-4">
<label class="radio-inline">
<input type="radio" ng-model="shippingVm.shipOption.val" name="shipOptions" ng-value="muted" />
I will deliver them to the Wizmo warehouse myself.
</label>
</div>
<div class="ng-class="shippingVm.shipOption.val">
stuff
</div>
</form>
my controller:
vm.shipOption = {val: "NOT-muted"};
This debugging line in the HTML checks to see if I'm getting the right value:
[{{shippingVm.shipOption.val}}]
It starts with [NOT-muted] - as it should. But the moment I select any radio button it goes blank.
According to the docs, clicking a radio should pass the radio's value into the model.
What am I missing?
Your ng-class is incorrect. See the below snippet for an example of what it should be. The second problem is that you want value instead of ng-value. From: https://docs.angularjs.org/api/ng/input/input%5Bradio%5D
value The value to which the ngModel expression should be set when selected. Note that value only supports string values, i.e. the scope model needs to be a string, too. Use ngValue if you need complex models (number, object, ...).
ngValue Angular expression to which ngModel will be be set when the radio is selected. Should be used instead of the value attribute if you need a non-string ngModel (boolean, array, ...).
.muted {
color: grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app>
<label>Chicken or the Egg?</label>
<div class="form-group">
<div class="radio">
<label>
<input type="radio" name="chickenEgg" value="chicken" ng-model="formData.chickenEgg">Chicken
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="chickenEgg" value="egg" ng-model="formData.chickenEgg">Egg
</label>
</div>
</div>
<div ng-class="{'muted': formData.chickenEgg === 'egg'}">
stuff
</div>
</div>
Oh, I see it now.
The radio buttons should have value="muted" not ng-value="muted".
ng-value is only used in a special case.

AngularJS Validation - ng-messages-multiple not displaying multiple errors

All,
I am working on an AngularJS form and am trying to see how the ng-messages directive works with ng-messages-multiple. I can't seem to get it to pick up multiple errors. I expect to see both the required and minimum errors at the same time but for some reason I only see required, then minimum. I posted the HTML below. I have the ng-messages included using bower, the script call in my index.html page, and I am injecting into my app.js module as required.
I am using AngularJS v1.3.2 in this project.
<div class="panel panel-default">
<div class="panel-heading">
<h1>Validation Test Form</h1>
</div>
<div class="panel-body">
<form class="form" name="form" role="form" ng-submit="submit(form)">
<div class="row">
<div class="form-group" show-errors>
<label for="name">Name:</label>
<input
class="form-control"
type="text"
name="name"
ng-model="formModel.name"
minlength="5"
required/>
<div ng-messages="form.name.$error" ng-messages-multiple class="has-error">
<div ng-message="required">Required!</div>
<div ng-message="minlength">Minimum length is 5</div>
</div>
</div>
</div>
<div class="row">
<div class="form-group">
<button class="btn btn-success" type="submit">Save</button>
</div>
</div>
</form>
</div>
<div class="panel-footer">
{{formError}}
</div>
</div>
Try to use ng-minlength instead minlength
<input
class="form-control"
type="text"
name="name"
ng-model="formModel.name"
ng-minlength="5"
required/>
instead
<input
class="form-control"
type="text"
name="name"
ng-model="formModel.name"
minlength="5"
required/>
EDIT
It is normal behaviour for ng-minlength directive, this directive validate only when we have not 0 size of input, entered a value it must be at least 5 characters long, but it's ok to leave the field empty, and, unfortunately, in anyway you don't achieve, that you want. I offer you to create your custom directive or see in direction ng-pattern directive with need behaviour, if you very want that showing two message.

Unique identifiers in dynamic form (ng-repeat)

I have a form with input texts that are looped in a ng-repeat.
For every input field there is a switch with which the user sets "Use default value" to YES/NO.
Every row of input fields are basically two fields, with one hidden one at a time, whether you want to show the default value (switch: YES, input text = disabled) or set a custom value (switch: NO)
I need each element to have a unique identifier to be able to save it on submit, for example **id="title_{{spec.id}}".
The switches work so that the switch-variable is used to create 2way binding, but it is the value of the checkbox within the Switch-DIV that will be saved to the database.
What I think I need to do is apply the spec.id value to the switch-variable="useDefaultValue_{{spec.id}}" and set the same value to the ng-show="useDefaultValue_{{spec.id}}" and ng-hide, but I don't know how to.
HTML:
<div class="row form-group" ng-repeat="spec in specsList">
<div class="col-xs-6 col-md-6">
<label for="specification_">{{spec.title}} <span ng-show="spec.unit.length">({{spec.unit}})</span></label>
<input class="form-control" type="text" name="title_{{spec.id}}" id="title_{{spec.id}}" placeholder="Not visible" ng-model="spec.value" ng-hide="useDefaultValue">
<input class="form-control" type="text" ng-model="spec.defaultValue" ng-show="useDefaultValue" disabled>
</div>
<div class="col-xs-6 col-md-6">
<label for="useDefaultValue_">Use default value</label> - {{spec.useDefaultValue}}<br />
<div class="switch" init-switch switch-variable="useDefaultValue">
<input type="checkbox" id="useDefaultValue_{{spec.id}}" name="useDefaultValue_{{spec.id}}" ng-model="spec.useDefaultValue">
</div>
</div>
</div>
Since your checkbox is backed by the row-dependent spec.defaultValue, you can come up with a simpler solution and don't need the switch. Just reference spec.useDefaultValue instead of your current useDefaultValue to directly access it.
<div class="row form-group" ng-repeat="spec in specsList">
<div class="col-xs-6 col-md-6">
<label for="specification_">{{spec.title}} <span ng-show="spec.unit.length">({{spec.unit}})</span></label>
<input class="form-control" type="text" name="title_{{spec.id}}" id="title_{{spec.id}}" placeholder="Not visible" ng-model="spec.value" ng-hide="spec.useDefaultValue">
<input class="form-control" type="text" name="title_{{spec.id}}" id="title_{{spec.id}}" ng-model="spec.defaultValue" ng-show="spec.useDefaultValue" disabled>
</div>
<div class="col-xs-6 col-md-6">
<label for="useDefaultValue_">Use default value</label> - {{spec.useDefaultValue}}<br />
<input type="checkbox" ng-model="spec.useDefaultValue">
</div>
</div>
As an aside, I would also use ng-if instead of ng-show and ng-hide to lighten the page and make the transitions smoother.
EDIT Submit function :
$scope.submit = function() {
angular.forEach(specsList, function(spec, index) {
if (spec.useDefaultValue) {
$scope.user[spec.title] = spec.defaultValue;
}
else {
$scope.user[spec.title] = spec.value;
}
});
User.save(user).$promise.then(function(persisted) {
// do some post-save cleanup
});
};
Of course, this is assuming you save spec values on the user. They could be stored somewhere else.

Angular.js required and ng-required not working for <textarea></textarea>

I can not get Angular.js required or ng-required to work. I want it to where if the user hits ok, they have to have some text in the textbox.
<div class="modal-body">
<p>Your change will be logged. Please provide a ticket number or comment for reference</p>
<div class="row">
<div class="span4">
<textarea type="text" class="form-control"
ng-model="commentBox.text"
ng-required="commentBox.text">
</textarea>
</div>
</div>
</div>
Scratching my head.....
two things:
make sure that value you are passing to ng-required is boolean (to be technically correct, it should evaluate to boolean)
<textarea type="text" class="form-control"
ng-model="commentBox.text"
ng-required="commentBox.textRequired">
</textarea>
//somewhere in your controller
$scope.commentBox.textRequired = true
you would need form.$invalid on your button
<button type="submit" ng-disabled="formname.$invalid" ng-click="onsubmit()"></button>
so to complete it
<ng-form name="exampleForm">
<textarea type="text" ng-model="commentBox.text" ng-required="true"></textarea>
<button ng-disabled="exampleForm.$invalid" ng-click="onsubmit()"></button>
</ng-form>
also without adding another prop, you could set it to
ng-required="!!commentBox.text"

Resources