Get value of dynamic nested checkbox in angular - arrays

I have created the dynamic nested checkboxes in Angular, I want to get the value of checkboxes if selected. I created a demo project in angular and facing the problem in json structure to achieve functionality.
sourcecode

There might be a more effective solution, but I would make an object with nested objects that are connected to your html.
For example:
countriesSport: CountrySports[] | undefined;
country: { id: 1, name: England, active: false, sports: [{ id: 1, name: soccer, active: false, selection: ENUM girl|boy|all}]}
You can save these values in a variable in your .ts file. In your html you can map over these values, for example like this:
<ul>
<li *ngFor="let country of countries>
<input
type="checkbox"
name="checkbox"
[checked]="country.active"
(change)="functionToDoExtraTHingsLikeToggleSubItems()"
/>
<ul>
<li *ngFor="let sport of country.sports>
<input
type="checkbox"
name="checkbox"
[checked]="sport.active"
(change)="functionToChangeSportsStuff()"
/>
</li>
</ul>
</li>
How you want to structure and style you input fields and which onces can be chosen or not, depends on your demands. The selection ENUM with girls|boys|all can also be an array of objects that has an active state.
When you initialize and destroy you component, you can save or map your object to other values.

Related

Dynamic ng-model binding to object properties inside ng-repeater

I require a bit of help with AngularJS syntax to make a dynamic checkbox selector bind to object properties.
Problem:
<div ng-repeat="level in vm.Settings.LevelList">
<input type="checkbox" ng-model="vm.Item.Level.{{level.ShortName}}" ng-change="CheckLevel()"> {{level.Name}}
<div>
Where items' level is just a key-value-pair object. It's important to note that not all levels may be applicable to an item but each item will have an object with all possible options as follows:
Item.Level = {
L1: false,
L2: true,
L3: false,
L4: false,
}
My vm.Settings.LevelList changes depending on the page that is loaded. To make things simple let's assume we have the following array to work with:
Settings.LevelList = [
{ Name: 'Level 2', ShortName: 'L2', SortOrder: 2, },
{ Name: 'Level 3', ShortName: 'L3', SortOrder: 3, },
]
My template spells out all possible options where I am using ng-if to hide ckeckboxes that are not relevant. While I am not expecting for levels to change often at the same time I do not want to spend my time tracking every template where level checkboxes apear. So, the following is what I currently have:
<div ng-if="conditon to hide L1"><input type="checkbox" ng-model="vm.Item.Level.L1" ng-change="CheckLevel()"> Level 1</div>
<div ng-if="conditon to hide L2"><input type="checkbox" ng-model="vm.Item.Level.L2" ng-change="CheckLevel()"> Level 2</div>
<div ng=if="conditon to hide L3"><input type="checkbox" ng-model="vm.Item.Level.L3" ng-change="CheckLevel()"> Level 3</div>
<div ng-if="conditon to hide L4"><input type="checkbox" ng-model="vm.Item.Level.L4" ng-change="CheckLevel()"> Level 4</div>
But what I want should be of the following form:
<div><input type="checkbox" ng-model="vm.Item.Level.L2" ng-change="CheckLevel()"> {{level.Name}}</div>
<div><input type="checkbox" ng-model="vm.Item.Level.L3" ng-change="CheckLevel()"> {{level.Name}}</div>
So, the repeater should only need to produce two checkbox options as per Settings.LevelList. Provided the model binds correctly checkbox for Level 2 should be checked (Item.Level.L2 = true).
Just in case someone wonders CheckLevel() just makes sure that at least one level option is selected. Also, I am working with AngularJS v1.5.8.
If your starting object has two items, and you're repeating through it, you would only get two iterations anyway, so it's straightforward. There was a spelling mistake in your repeat, where you had 'ShortName' but in the date you had 'ShartName' so I've amended the input to display that.
<div ng-repeat="level in vm.Settings.LevelList">
<div>
<input type="checkbox" ng-model="vm.Item.Level[level.ShartName]"
ng-change="CheckLevel()" /> {{level.Name}}
</div>
<div>

Find the object in the $scope that have a key starting with a certain string?

I have a list of text field like this
<ul>
<li><input type="text" name="option1" ng-model="option1" /></li>
<li><input type="text" name="option2" ng-model="option2" /></li>
</ul>
I'd like to find all of the option* that are in the $scope
Thank you in advance for the answer
I would make an array which will hold the input data and then add a loop to iterate over this array in html. You will then not need to search in scope for specific objects, you will have the array ready.
$scope.allOptions = [
{name: 'option1', text: ''},
{name: 'option2', text: ''}
];
And then:
<ul>
<li ng-repeat="option in allOptions"><input type="text" name="{{option.name}}" ng-model="option.text" /></li>
</ul>
The problems is that I don't know the number of the text fields in the list. The application has by default two list but there is also a button that permit the user to add new options programmatically. So with Jquery i add in every text field a progressive number in the ng-model. The first ng-model=option1, the second option2, ...
I recommend to use angular then (to add another input).
$scope.addInput = function(){
var n = $scope.allOptions.length;
$scope.allOptions.push({name: 'option'+(n+1), text: ''});
};
<button ng-click="addInput()">Awesomeness is here</button>
There's a few ways to do this.
See this working jsFiddle
The first method I'm showing you would be the natural next step to the way you've done it, and would allow you to access the values as you request.
First, bind your inputs to an array, like so:
<ul>
<li><input type="text" name="option[1]" ng-model="option[0]" /></li>
<li><input type="text" name="option[2]" ng-model="option[1]" /></li>
<li><input type="text" name="option[3]" ng-model="option[2]" /></li>
</ul>
Don't forget to declare your variable as an array in the controller:
$scope.option = [];
Then, in your controller, you can access them via $scope.option.
A more advanced, and simpler / easier to maintain method might be to useng-repeat, which is very powerful. ng-repeat documentation
To use ng-repeat:
First, set up the array of objects in your controller, like so:
$scope.rOptions = [
{name: 'option1', val: ''},
{name: 'option2', val: ''},
{name: 'monkey', val: ''}
];
Then, you can output the HTML with a simplified set of markup:
<ul>
<li ng-repeat="rOption in rOptions"><input name="{{rOption.name}}" ng-model="rOption.val"></li>
</ul>
And, in your controller, you can access the values via $scope.rOption.
You can check out the fiddle above to see how these two work, and how the data can be accessed.

How can I access ngRepeat iterator scope from filter filter

I'm writing some application that is a bit like e-shop. I have a list of entities and checkboxes to filter them. And I want to make that checkbox-filters be some sort of universal. I plan to write an expression in checkbox's attribute and then eval in within the scope of each entity by using filter filter in ngRepeat. The problem is how to access the scope of an entity from that filtering function. For example:
My data (JS):
food = [
{
category: 'fruits',
name: 'Apple'
},
{
category: 'vegetables',
name: 'Potato'
}
]
My filter checkbox (HTML):
<label>
Fruits:
<input type="checkbox" data-filter="category == 'fruits'" />
<label/>
My list (HTML):
<ul>
<li ng-repeat="item in food | filter:customFilterFunction">
</li>
</ul>
My filter function (JS):
$scope.customFilterFunction = function(item) {
// here I want to eval that expression written in checkbox's attribute
// within the scope of each item in food array.
// The problem is not how to access that expression,
// but how to access the scope of item in food array.
}
Of course, I can create new scope from $rootScope each time I apply that filter function, and then pass all item properties to that new scope, and then eval that expression in this scope. But I think it would consume a lot of memory because of creating a lot of new scopes each time user changes the filters.
Do you know a better solution?
What's about following, without cusrtom filter?
Fruits & Apple:
<input type="checkbox" data-ng-model="fil" data-ng-true-value="{{category = 'fruits';name = 'Apple'}}" data-ng-false-value="" />
Fruits:
<input type="checkbox" data-ng-model="fil.category" data-ng-true-value="fruits" data-ng-false-value="" />
Vegetables:
<input type="checkbox" data-ng-model="fil.category" data-ng-true-value="vegetables" data-ng-false-value="" />
<ul>
<li ng-repeat="item in food | filter:fil">{{ item.name }}</li>
</ul>
See in action: plnkr

How to bind ng-model to ng-checked boxes

I am having a problem binding Angular ng-check to ng-model, that is ng-model does do not recognize the selected state of my check boxes.
Here is a description(Its a much larger code base but I have tailored to minimize code).
On page load in JavaScript I initialize my products and set the default values:
$scope.products = {}
$scope.SetProductsData = function() {
var allProducts;
allProducts = [
{
id: 1,
name: "Book",
selected: true
}, {
id: 2,
name: "Toy",
selected: true
}, {
id: 3,
name: "Phone",
selected: true
}]
I have a master control in my view that list a check box for each 3 products(Book,Toy and phone):These are checked by default
<div style="float:left" ng-init="allProducts.products = {}" >
<div ng-repeat="p in Data.products">
<div style="font-size: smaller">
<label><input id="divPlatorm" ng-model="products[p.name]" ng-init="products[p.name] = true" type="checkbox"/>
{{p.name}}</label>
</div>
</div>
</div>
Then a table that have the same products repeated in rows:
<div ng-repeat="line in lineProducts" ng-init="line.products = {}">
<div id="sc-p-enc" ng-repeat="p in Data.products">
<div id="sc-p-plat" style="font-size: smaller">
<label id="pl-label"><input ng-checked="products[p.name]" ng-model="line.products[p.name]" ng-init="line.products[p.name] = true" type="checkbox"/>
{{p.name}}</label>
</div>
</div>
</div>
When I check/unchecked the master products the corresponding check boxes changes in the rows. So if I have 100 rows with (Book,Toy and phone) the unchecked Toy I can see where all toys are unchecked in the rows.
When I send the data to my controller I can still see all Toys = true even though they were unchecked.
If I physically go to the row then unchecked each toy and send the data to my controller Toys = False.
How can I get the check boxes selected state to change when controlled from the master check-boxes?
I have followed the post found here but I dont think this applies to my scenario:
AngularJS: ng-model not binding to ng-checked for checkboxes
It seems the ng-checked in the table is binding to products[p.name], which the ng-model in your master control in the view also binding to. But the ng-model in your table is binding to another property, line.products[p.name].
I think you probably don't need ng-checked in the table since each item has its own ng-model. So you might change your table view to
<label id="pl-label"><input ng-model="line.products[p.name]" type="checkbox"/>{{p.name}}</label>
and in the controller, change the corresponding value of line.products[p.name] every time the value of products[p.name] is changed.
I just solved this problem myself by using "ng-init" and "ng-checked" ---
ng-checked - 'checked' the checkbox as form was loaded
ng-init- bound my checkbox html value attribute to the model
There is a comment above stating that its not good to use ng-init in this manner, but not other solution was provided.
Here is an example using ng-select instead of ng-checked:
<select ng-model="formData.country">
<option value="US" ng-init="formData.country='US'" ng-selected="true">United States</option>
</select>
This binds "US" to model formData.country and selects the value on page load.
If I understand the functionality you are trying to cover the following fiddle might help you. Here is the code:
<div style="float:left" ng-app ng-init="products = [
{
id: 1,
name: 'Book',
line: 'Books',
selected: true
}, {
id: 2,
name: 'Another Book',
line: 'Books',
selected: true
}, {
id: 3,
name: 'Toy',
line: 'Toys',
selected: false
}, {
id: 4,
name: 'Another Toy',
line: 'Toys',
selected: false
}, {
id: 5,
name: 'Phone',
selected: true
}];lineProducts = ['Toys', 'Books']" >
<div style="float:left">
<div ng-repeat="p in products">
<div style="font-size: smaller">
<label>
<input ng-model="p.selected" type="checkbox"/>
{{p.name}}
</label>
</div>
</div>
</div>
<div ng-repeat="line in lineProducts">
{{line}}
<div ng-repeat="p in products | filter:line">
<div style="font-size: smaller">
<label>
<input ng-model="p.selected" type="checkbox"/>
{{p.name}}
</label>
</div>
</div>
</div>
</div>
Also why do you have ids in your html? With angular there is no need in ids, and considering that they are inside ng-repeats they will be ambiguous and therefore useless anyway.
I also agree with Nikos about usage of the ng-init. I used it in my jsfiddle because I am lazy, I would not use it in the production code
You should use ng-model there that would provide you two way binding. Checking and unchecking the value would update the value of product.selected
<input type="checkbox" ng-model="p.selected"/>

Angular - Filtering with checkboxes

I am new to Angular and i just cant wrap my head around that problem.
I have several checkboxes which will have a unique value each, like so:
<label ng-repeat="c in classes">
<input type="checkbox" ng-model="query" ng-true-value='{{c.name}}'>
<span>{{c.name}}</span>
</label>
Next i have this set of divs that should be filtered on a specific value like card.name , like so:
<div ng-repeat="card in cards | filter:query">
<h2>{{card.name}}</h2>
<p><em>{{card.text}}</em></p>
</div>
When checkbox with value 'Peter' is checked, all cards with card.name=Peter are shown. When checkbox 'Peter' and 'John' are shown all cards with card.name=Peter and =John are shown. How can i realize this?
I guess its more of a general concept/markup question...
You don't need to have two different variables, in fact that is the problem. Angular doesn't know how to tie them together.
The filter can look deep into the object for a specific key set to a specific value. In my example the filter looks for this particular selected attribute, only showing ones that are set to true Keeping everything in the same object keeps everything tied together.
<label ng-repeat="c in classes">
<input type="checkbox" ng-model="c.selected" />
<span>{{c.name}}</span>
</label>
<div ng-repeat="card in classes | filter:{selected:true}">
<h2>{{card.name}}</h2>
<p><em>{{card.text}}</em></p>
</div>
Here is the data:
$scope.classes = [{
name: "John",
text: "Something about John"
},{
name: "Peter",
text: "Something about Peter"
}];
Note: that a selected attribute is added to each object when it is selected. This is the key we are filtering on.
Working example: http://jsfiddle.net/TheSharpieOne/y2UW7/
UPDATE:
After re-reading the question, it appeared to me that there would be multiple cards for the same name. A different approach would be needed.
In this case, multiple variables are needed, a list of checkboxes and a list of "cards". We also need a var to track which boxes are selected.
In this case we use a function to filter the list as 1 checkbox could change many "cards"
Example: http://jsfiddle.net/TheSharpieOne/y2UW7/1/

Resources