Unique identifiers in dynamic form (ng-repeat) - angularjs

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.

Related

Angularjs form scope bug

I have a Angularjs form with a list with names.
When I click on a name the form will change with here profile.
When I change one input and don't save it and I click on a other profile every thing change except the one input that has changed.
<form class="form-horizontal bordered-row" >
<div class="form-group">
<label class="col-sm-4 control-label">Naam</label>
<div class="col-sm-6">
<input type="text" class="form-control" id="" value="{{gegevens.naam | capitalize}}">
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">Categorie</label>
<div class="col-sm-6">
<select class="form-control">
<option ng-repeat="x in producten_categorie" value="{{x.value}}" ng-selected="gegevens.categorie == x.value">{{x.name}}</option>
</select>
</div>
</div>
<div class="form-group pad25L">
<button class="btn btn-info" ng-click="productAlgemeen_update(gegevens.naam);">Save</button>
</div>
</form>
And the change scope:
$scope.productGegevens = function(product){
$http.post("php/producten-locatie.php", {'id':product.id}).then(function(response){
$scope.producten_locatie = response.data.records[0];
$scope.gegevens = {
id:product.id,
naam:product.naam,
categorie:product.categorie,
straatnaam:$scope.producten_locatie.straatnaam,
huisnummer:$scope.producten_locatie.huisnummer,
postcode:$scope.producten_locatie.postcode,
stadsnaam:$scope.producten_locatie.stadsnaam
};
});
}
Please note that input data needs to bind with ng-model whereas you are entering your input with value tag. it means the value is rendered in html not in model, so when you click on other profile UI can not detect the change. Please use ng-model for input value not value tag of input box.

Input text is empty using ng-model if value is provided

I passed an array value in my view with $userdata.
In my view, there's a button there that will show a modal when triggered. This modal will show the user data using the $userdata variable.
Now, I used angular js for my form inputs.
For example:
div class="form-group">
<label for="company_name" class="col-sm-12 control-label">Company Name</label>
<div id="company_name" class="col-sm-12">
<input type="text" class="form-control" name="company_name" value="{{$userData['company']['name']}}" ng-model="user.company_name" ng-required="true">
</div>
<div class="col-sm-12">
<span ng-show="userForm.company_name.$error.required && userForm.company_name.$touched"><br> <small><i>Name field is required</i></small></span>
</div>
</div>
The problem here is the input is not showing any value.
Why so? But when I removed the ng-model and just used a plain input field, the value will be shown.
You have to remove value="..." from input, ng-model will control it. look at this example.
<input type="text" class="form-control" name="company_name" ng-model="user.company_name" ng-required="true">

Angular bootstrap conditionally-required fields

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>

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.

Issue with ng-model and ng-repeat, duplicate forms

I have a page where multiple forms are created based on ng-repeat. Everything works fine until write something into the input and everything gets duplicated on all the other repeated forms input elements. I have used ng-model="Notify.message" which is nothing but object which takes the value from the input and sends to control on button submit and hence rest of the logic.
I am looking for when if one form is been filled, other forms should keep quite and shouldn't duplicate the values written in input text of form 1.
Here is the code:
<div data-ng-show="alluserposts.length > 0">
<div id="b{{userpost.id}}" data-ng-repeat="userpost in alluserposts" >
<div class="row" style="margin-left: -5px">
<form class="text-center" role="form" id=f1{{userpost.id}} name="userForm"
ng-submit="notify(userForm.$valid, userpost, apiMe)" novalidate>
<div class="row">
<div class="col-xs-8 col-md-4">
<div class="form-group">
<input data-container="body" data-toggle="popover" data-placement="top"
data-content="Any message which you would like to convey to post owner"
type="text" ng-model="Notify.message" data-ng-init="Notify.message=''"
id="u{{userpost.id}}"
placeholder="Enter a Message or Phone number" class="form-control"
required>
<p ng-show="userForm.name.$invalid && !userForm.name.$pristine" class="help-block">It is
required.</p>
<script>$(function () {
$("[data-toggle='popover']").popover();
});
</script>
<input type="hidden" ng-model="Notify.loggedInEmail"
ng-init="Notify.loggedInEmail = result.email"/>
<input type="hidden" ng-model="Notify.postId" ng-init="Notify.postId = userpost.id"/>
<input type="hidden" ng-model="Notify.destEmail"
ng-init="Notify.destEmail = userpost.userEmail"/>
</div>
</div>
<div ng-show="loginStatus.status == 'connected'" class="col-xs-4 col-md-2">
<button class="btn btn-primary" ng-disabled="userForm.$invalid || !userForm.$dirty"
type="submit">
Notify Post Owner
</button>
</div>
</div>
</form>
</p>
</div>
</div>
</div>
</div>
Issue fiddle - jsfiddle
Here you can when something is written in one input, other gets filled too :( . Also Notify is a Java mapped object and message is a variable inside it. Pls let me know how can this can be segragated!
You bind all of your inputs to same variable on $scope.
You must bind every text box to a distinct variable on $scope:
View:
<ul ng-repeat="post in posts">
<li>{{$index}}
<input type="text" ng-model="emails[$index]"/>
</li>
</ul>
Controller:
$scope.emails = [];
I am also at the starting phase of angularjs.
I have faced the same issue few days ago and resolved it by providing dynamic model name in ng-model like
<input type="text" ng-model="Notify[post.userEmail]" ng-init="Notify[post.userEmail] = post.userEmail" />
Working fiddle: Fiddle

Resources