Angular 2: Array with checkbox not working properly - arrays

I'm binding one array with Checkbox. However, When I try to change bool attribute for single element of array but it changes for all elements.
My HTML Component is as below.
<div class="col-sm-4" *ngFor="let karyalay of karyalayListFinal">
<div class="checkbox-fade fade-in-primary">
<label>
<input formControlName="karyalay_group" type="checkbox" name="karyalaysCheckbox" value="{{karyalay.karyalayId}}" [(ngModel)]="karyalay.isChecked"
(click)="callEvents(karyalay.karyalayId)">
<span>{{karyalay.karyalayName}}</span>
</label>
</div>
</div>
Now I'm trying to change value of single or selected element as below.
for (let karyalay of this.karyalayListFinal) {
let tempInd = _.findIndex(this.roleMasterEventList, {'KARYALAY_ID': karyalay.karyalayId});
if (tempInd > -1) {
this.karyalayListFinal[tempInd].isChecked = true;
}
}
Actually, if tempInd > -1 then and then only that element's value should be changed. But it changes for all.
Don't know whether this is ngModel issue or what?
Thanks

Putting input tag inside *ngFor will create multiple input tags. And name property for input must be different for all. As HTML configure changes for input property using the name property. So, make this name property unique for every input by keeping a name field in the model passed in *ngFor.
And target the checked property instead of ngModel. And do something like
[checked]="yourmodel.isChecked", keep default value of isChecked property in your model as false.
Hope, it helps.

Sorry, but it seems that your approach is too complicated.
I don't know when you call this for each-loop, but I suppose that you already know or have the id you are searching for at this point. Let's call it searchID.
If you want to find the object with the matching id simply use the for each loop as follows:
this.karyalayListFinal.forEach( el => {
if(el.karyalayId === searchID) {
el.isChecked = true;
}
});
That should solve your problem.

you are running this loop for all the elements in "this.karyalayListFinal"
for (let karyalay of this.karyalayListFinal) {
let tempInd = _.findIndex(this.roleMasterEventList, {'KARYALAY_ID': karyalay.karyalayId});
if (tempInd > -1) {
this.karyalayListFinal[tempInd].isChecked = true;
}
}
might be possible that the condition "tempInd > -1" is satisfied for all the elements in "this.karyalayListFinal" and hence all are changing.

I used [checked]="karyalay.isChecked" instead of ngModel in the HTML Code and it started working.

"name" attribute written in input field must be unique for every element created by the loop
you must bind the id of every object coming in an array "karyalayListFinal" to make them unique.

Related

Bind a list of checkboxes in AngularJS

I have a list of checkboxes as following :
<div ng-repeat="formationType in formationTypeList">
<label>
<input type="checkbox" class="md-warn md-align-top-left"
ng-model="formationSelection[$index]"
ng-true-value="{{formationType}}"
name="formationSelection[]">
{{ formationType.nom }}
</label>
</div>
As you can see this checkboxes are initialized with values in formationSelection[] array.
And when I check some checkbox the value of this checkbox is added to that array.
The formationTypeList contains a list of objects, each object is attached to a checkbox.
In my scenario the first time I have the formationSelection[] empty so when I check some checkboxes and I send my form the values in that array will be stored in a database, and when I back o my application I want to see the checkboxes I've selected so I populate that array whith values from the database and then I can see the ones wich was selected.
The problem I have is the checkboxs are only selected in one case if I have in formationSelection[] the first element or the first, second elements or the first, second and third elements, but when I have for example the second and the fourth elemnts, they are not selected.
this is a plunker for the working case :
http://plnkr.co/edit/I7NK8Tkw3Rzwh1Zj2X78?p=preview
and this is a plunker for the non working case :
http://plnkr.co/edit/82FDQlhTtd09scs9cCDz?p=preview
Why I'm getting this behavior, and how can I solve it ?
Keep formationSelection length the same as formationTypeList, it will work.
$scope.formationSelection = (function(selection,list){
var result = new Array(list.length);
Array.prototype.map.call(selection,function(val,index){
var pos = Array.prototype.map.call(list,function(v,i){
return v.codeFormation;
}).indexOf(val.codeFormation);
result[pos] = val;
});
return result;
})($scope.formationSelection,$scope.formationTypeList);
Plunker here.

Angular JS Text Field Input Change - Watch

I have a list of text fields with an empty text field at the end, bound to an array. I need to detect text entry on the empty text field so when a user starts typing a value, I add another empty element to array so the user always has another field ready to work with.
Should I use $watch or ng-change to see the change go down and add the element accordingly? I know $watch is always firing so it seems like that may be a bad option.
<div ng-repeat="variation in productEditorModel.ColorVariations">
<div class="form-inline">
<input type="text" id="txtVariationName" placeholder="Name" name="variationName" ng-model="variation.VariationName" required class="form-control">
</div>
</div>
Considering performance aspect, you should better use ng-change because it will work as you've added change listener on the input like $('input').change(...) just as you mentioned.
Considering UX and functionality aspects it is better and easier to simply use $scope.$watch('model', ...) in controller.
But still I suppose it depends on how many inputs you will have. I think there is no really big difference with even 100+ inputs because you just comparing strings, I don't think that user will struggle with delays as he types.
Why don't you bind the array to an ng-repeat of input elements? This way the binding will work automatically.
thanks for the input, ng-change worked best.
ng-change="update(variation,$index);"
$scope.update = function (variation, index) {
if (!angular.isUndefined(variation.VariationName)) {
if (variation.VariationName.length > 0) {
$scope.addVariation(variation.VariationTypeId);
} else {
$scope.productEditorModel.ColorVariations.splice(index, 1);
$scope.removeVariation(index, variation.VariationTypeId);
}
} else {
$scope.removeVariation(index, variation.VariationTypeId);
}
}

Can't get Angular select to update with selected value

I'm using selects to allow a user to switch between events and years. Each change will pull appropriate data from the server, return and update the page. However, the select box goes from the selected value to an empty value. I've looked at numerous solutions and they aren't working.
<select
ng-model="eventName"
ng-options="item.value for item in eventOptions track by item.value"
ng-change="changeEvent(eventName.value)">
</select>
This is the changeEvent function:
$scope.changeEvent = function(eventName){
$scope.eventName = eventName; //wrongly assumed this would update the selected value
$scope.getData($scope.eventName,$scope.eventYear); //this returns the json - correct
$scope.updateSelected(); //meant to update the select field value on the page - fails
};
$scope.eventName or $scope.eventYear values will properly update on a change, but has no effect on the page. The selects just empty of a selected value.
UPDATED (with corrected code)
I wanted to post the changes I made more clearly than the comment allows.
I removed the object param "value" from the options and the argument from the function call (eventName.value).
<select
ng-model="eventName"
ng-options="item for item in eventOptions track by item"
ng-change="changeEvent()">
</select>
And the changeEvent function gets simplified to:
$scope.changeEvent = function(){
$scope.getData($scope.eventName,$scope.eventYear);
};
It all works as expected! Thanks to all, especially Delta who got me looking at it the right way.
So, your event name variable is set to be item. not item.value so instead of passing in changeEvent(eventName.value) try passing in changeEvent(eventName). either way the value you are passing into your method doesnt match the value of your model's variable
item.value for item in eventOptions track by item.value
so for this statement, you are saying make my options ng-model=item but make their value=item.value so they show what you want them to show but still have all the information you need from each one.
Upon further inspection is looks like you dont need:
$scope.eventName = eventName;
$scope.updateSelected();
Angular should be updating your eventName for you, you just need to call the change method.
I'm not sure you need:
ng-change="changeEvent(eventName.value)"
if you use ng-options the model will be updated in the scope automatically on selection. You could watch the value in the controller if you want to do other stuff when it changes:
$scope.$watch('eventName', function() {
//do stuff
});

How can I accomplish this task in AngularJS?

I am attempting to accomplish a task where I am using AngularJS so I am not sure how to implement potentially needed Javascript or if there is a way with using AngularJS.
I have this input:
<input type="number" ng-model="myCount" ng-disabled="button" min="1" value="1" id="myValue">
This code takes the value input by the user and places it in a variable:
$scope.myCount = document.getElementById("myValue").value;
Now, what I want is based on the number input, I want an array/object created for the number from the variable. For example:
for(i=0;i<myCount.length;i++){
$scope.trackObject=[
{name:i + "Objects"}
]
}
Here is what I am trying to accomplish with this:
<ul class="nav nav-tabs" id="pizza_tabs" role="tablist" ng-repeat="x in countPizzas">
<li class="active">{{x.name}}</li>
</ul>
Sorry, I don't think I very well explained what I am trying to accomplish!
I want there to be a tab that contains the text "# Object", for each object created which the number of objects created is based on the user input. Does that make sense? So, if the user inputs 3, then 3 objects will be created, which I will be able to assign a name and whatever other properties to. 3 tabs are thusly created for the user to toggle through that will contain these properties. I hope that helps!
"what I want is based on the number input, I want an array/object created for the number from the variable"
for(i=0;i<myCount.length;i++){
$scope.trackObject=[{name:i + "Objects"}]
}
//Try this
var name;
for(i=0;i<myCount;i++){ //because myCount is a number
name = i+"Objects";
$scope.trackObject.push({name:name}); //add to the array
}
Now for your last snippet, I didn't understand what you want to accomplish there.
I am confused by your question.
You have already set the ngModel to myCount so whatever you have typed into the input box would have been set to the ngModel - 'myCount'
There is no need to use jquery to get the value as such
"$scope.myCount = document.getElementById("myValue").value;"
As for the second part, i believe the user "I_Wrote_That" has already replied you on how to create an array of objects based on the input.
At first, angular supports two way data binding. So you need not get the value of the element manually using document.getElementById etc.
$scope.myCount = document.getElementById("myValue").value;
Instead the value will be available in myCount by default.
Now to generate the objects based on count:
<ul class="nav nav-tabs" id="pizza_tabs" role="tablist">
<li class="active">{{x.name}}</li>
</ul>
Now in your controller:
$scope.generateCounts = function(myCount) {
$scope.trackObject = [];
for(var i=0; i < myCount; i++) {
$scope.trackObject.push({name : i+"objects"});
}
return $scope.trackObject;
}
But this will not work still, it will give you duplicate key error.
So in your HTML, use track by $index
<li class="active">{{x.name}}</li>

Can't get Angular-xeditable Editable-Select to Select the current item when it is bound to a nested JSON object

I can't get the Angular-xeditable Editable-Select to Select the current item when it is bound to a nested JSON object. Data all saves fine, but it just doesn't show up the currently selected item in the Select box, which is driving me nuts, as I am sure I am missing something obvious. I have created a JSFiddle here:
http://jsfiddle.net/NfPcH/1031/
This is the code:
<span editable-select="data.organisation.OrganisationType"
e-ng-options="type.Name for type in data.types">
{{data.organisation.OrganisationType.Name}}
</span>
These are the 2 data objects:
$scope.data.organisation = {
"Id":1,
"Name":"My Organisation",
"OrganisationType":{"Id":2,"Name":"Internal"}
}
$scope.data.types = [
{"Id":1,"Name":"Client"},
{"Id":2,"Name":"Internal"},
{"Id":3,"Name":"Cold"}
]
It works fine when I bind it to the ID within the Nested Object, but then it only changes the Id in my nested object, and I then have to manually filter and change the Name part of the object, which works, but I am sure there must be a better way.
When the item is selected $data is loaded with the id of the item selected. You can use this to retrieve the value after the selection is made.
<span editable-select="data.organisation.OrganisationType"
e-ng-options="type.Name for type in data.types">
{{ findTypeName($data) || data.organisation.OrganisationType.Name}}
</span>
You can then define findTypeName in your controller
$scope.findTypeName = function(id) {
var found = $scope.data.types.filter(function(t){
return (t.Id === id);
});
return found.length ? found[0].Name : null;
};
The trick resides on using the object on the select's ng-options (e.g. 'obj as obj.title') and not a property of the object, so that when an item gets selected, it will assign the whole object to the model and not the property.
The problem with this approach is, that you cannot just compare objects (because comparing an object always compares their reference, not the "contents", so that obj1 == obj2 will never be true, unless they are exact the same object), so the other trick needed here is to use track by <some-id-property> on the ng-options. So your editable would look like this:
<span editable-select="data.organisation.OrganisationType"
e-ng-options="type as type.Name for type in data.types track by type.Id">
{{data.organisation.OrganisationType.Name}}
</span>
Beware that on your JSFiddle you're using a very old version of angular (where track by is not supported), so I created a new one using 1.2, which is the oldest angular version supporting track by:
http://jsfiddle.net/NBhn4/170/

Resources