Validate dynamically created Check box and Radio buttons - angularjs

I have an application in which dynamically check boxes and radio buttons get generated based on the data sent from the server. The number of check box/radio button displayed can increase up to 20 (in a single group).
My question is, what is the best method to validate a group of check box, radio button which are generated dynamically and also they are part of the same form element.
Below is the code which I am using
The data is of similar to the format below
$scope.values = [
{ Type: 'CheckBox',
IsRequired: true,
Id:1,
Options: [
{
Id: 11,
Text: 'Test 1',
},
{
Id: 12,
Text: 'Test 2',
},
{
Id: 13,
Text: 'Test 3',
},
{
Id: 14,
Text: 'Test 4',
}
]
},
{ Type: 'Radio',
IsRequired: 'true',
Id: 2,
Options: [
{
Id: 21,
Text: 'Radio 1',
},
{
Id: 22,
Text: 'Radio 2',
},
{
Id: 23,
Text: 'Radio 3',
},
{
Id: 24,
Text: 'Radio 4',
},
]
},
];
And for building the view I am using the below code for generating check boxes
<div ng-class="{ 'has-errors' : testForm.cb_{{q.Id}}.$invalid && {{q.IsRequired}} == true, 'no-errors' :
testForm.cb_{{q.Id}}.$valid && {{q.IsRequired}} == true}">
<ion-checkbox class="item" ng-repeat="opt in q.Options"
name="cb_{{q.Id}}"
ng-required="q.IsRequired"
ng-model="options">
{{opt.Text}}
</ion-checkbox>
</div>
Below code for radio button
<div ng-class="{ 'has-errors' : testForm.rb_{{q.Id}}.$invalid
&& {{q.IsRequired}} == true, 'no-errors' : testForm.rb_{{q.Id}}.$valid
&& {{q.IsRequired}} == true}">
<ion-radio ng-repeat="opt in q.Options"
ng-model="choice"
name="rb_{{q.Id}}"
ng-value="opt.Id"
ng-required="true">{{opt.Text}}
</ion-radio>
</div>

Related

Angular filter array inside array

I'm working in an Angular 9 app and I need to filter an array based on another array inside each object. To understand me here is an example of the array
const products = [
{
name: 'Product 1',
origins: [
{ quantity: 1, name: 'Pack 1' },
{ quantity: 1, name: 'Pack 2' },
]
},
{
name: 'Product 2',
origins: [
{ quantity: 1, name: 'Pack 1' },
{ quantity: 1, name: 'Pack 2' },
]
},
{
name: 'Product 3',
origins: [
{ quantity: 1, name: 'Inventory' },
{ quantity: 1, name: 'Pack 5' },
]
}
]
So I got a filter input which has to filter the products by a coincidence on the name of the product or one or more origin's name.
For example, if I type "2" the result array must be:
products = [
{
name: 'Product 1',
origins: [
{ quantity: 1, name: 'Pack 2' },
]
},
{
name: 'Product 2',
origins: [
{ quantity: 1, name: 'Pack 2' },
]
}
]
Because the character "2" is in the name of origin of Product 1 and Product 2, also is present in the name "Product 2"
I tried many things to do this but the result array always modifies my original array when I put this in a pipe
<input type="text" [(ngModel)]="searchtext">
<div *ngFor="let p of (saleProducts | filter : searchtext); let i = index">
{{ p.name }}
<div *ngIf="p.origins.length > 0">
<div *ngFor="let o of p.origins">
{{ o.name }}
</div>
</div>
</div>
What is the best (simple and optimized) way to filter this using a pipe without modifying the original array?
below a pipe implementation to with a default key origins:
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'filter'
})
export class FilterPipe implements PipeTransform {
transform(value: any[], searchName: string, key = 'origins'): any[] {
const products = []
value.forEach(product => {
const matches = product[key].filter(({ name }) => name === searchName)
if (matches.length) {
products.push({ ...product, [key]: matches })
}
})
return products
}
}

Why ngFor with filter pipe cause infinite loop?

i have this situation.
CheckboxesComponent
<section
*ngFor="let group of model.groups | myfilter:term; let index = index">
<div>
<mat-checkbox
[checked]="group.allChecked"
[ngModel]="group.allChecked"
color="primary">
{{ group.name }}
</mat-checkbox>
</div>
<div>
<ul>
<li *ngFor="let checkbox of groups.checkboxes;">
<mat-checkbox
[checked]="checkbox.check"
[(ngModel)]="checkbox.check"
color="primary">
{{ checkbox.displayName }}
</mat-checkbox>
</li>
</ul>
</div>
</section>
In a second component i have
<mat-form-field
appearance="outline">
<mat-label>
Search by
</mat-label>
<input
matInput
type="text"
[(ngModel)]="filter">
<mat-icon matPrefix fontIcon="icon-search"></mat-icon>
</mat-form-field>
<app-checkbox-group
[datasource]="claims"
[term]="filter"
>
</app-checkbox>
and this pipe
#Pipe({
name: 'roleFilter',
pure: false
})
export class myfilter implements PipeTransform {
transform(groups: [], term: string): [] {
if (!term) {
return groups;
}
return groups
.map(obj => {
return Object.assign({}, obj, {
checkboxes: obj.checkboxes.filter(el => el.displayName.includes(term))
})
})
.filter(obj => obj.checkboxes.length > 0)
}
}
and groups is a dataset like this
[
{
name: 'Group 1',
allChecked: false,
isIndeterminate: false,
checkboxes: [
{
check: true,
displayName: 'first',
name: 'first',
id: '1',
isMandatory: false
},
{
check: false,
displayName: 'second',
name: 'second',
id: '2',
isMandatory: false
},
{
check: false,
displayName: 'third',
name: 'third',
id: '3',
isMandatory: false
},
{
check: false,
displayName: 'fourth',
name: 'fourth',
id: '4',
isMandatory: false
},
{
check: false,
displayName: 'fifth',
name: 'fifth',
id: '5',
isMandatory: false
},
{
check: false,
displayName: 'sixth',
name: 'sixth',
id: '6',
isMandatory: false
},
{
check: false,
displayName: 'seventh',
name: 'seventh',
id: '7',
isMandatory: false
},
{
check: false,
displayName: 'eighth',
name: 'eighth',
id: '8',
isMandatory: false
},
]
}
]
When i start typing on the input filter, to reduce the dataset, if i start typing with a letter that not match with any displayName all groups are hidden and it's work like expected.
The problem appears when i start typing with a letter that match with some of the displayName property of the checkboxes.
I don't understand why but all page freeze and the map function is called infinite times.
The problem seem to be in
Object.assign in the map method. Because if i change this line with
obj.checkboxes = checkboxes: obj.checkboxes.filter(el => el.displayName.includes(term)) it works but replace the original checkboxes with the filtered one.
In accordion to #Andrei comment
try to add trackByIndex(idx) {return idx;} method and pass it to both ngFor insatnces like this *ngFor="let checkbox of groups.checkboxes; trackBy: trackByIndex"
The solution was using the trackBy pipe on both *ngFor directives.

How to select multiple selected value from select option

My controller code looks like
$scope.items = [{
heading: 'Sports',
types: [{
name: 'Football',
}, {
name: 'Persie',
}, {
name: 'Ronaldo',
}, {
name: 'Messy',
}],
id: '1'
}, {
heading: 'Cricket',
types: [{
name: 'Tendulkar',
}, {
name: 'Lara',
}, {
name: 'Ponting',
}],
id: '2'
}];
My view contains something like this :
How can I get the selected values of options when user clicks submit button
Here is the jsfiddle
I used ng-repeat to build the select and ng-options to fill them, you then have to use the relative ng-model to get the selections.
HTML:
<div ng-app ng-controller="MyCtrl">
<select class="select fancy" ng-repeat="(i, item) in items" ng-model="searchOption[i]" ng-options="type.name for type in item.types"></select>
<button ng-click="submitIt()">Submit</button>
</div>
Javascript:
function MyCtrl($scope) {
$scope.submitIt = function () {
console.log($scope.searchOption);
};
$scope.searchOption = [];
$scope.items = [{
heading: 'Sports',
types: [{
name: 'Football',
}, {
name: 'Persie',
}, {
name: 'Ronaldo',
}, {
name: 'Messy',
}],
id: '1'
}, {
heading: 'Cricket',
types: [{
name: 'Tendulkar',
}, {
name: 'Lara',
}, {
name: 'Ponting',
}],
id: '2'
}];
}

Angular 1.3 filter list of objects with array attribute

I hope someone can help me.
For my current project in angular 1.3 I'm using this list:
$scope.myList = [{
id: "obj1",
content: [{
id: 1,
name: 'attr 1'
}, {
id: 2,
name: 'attr 2'
}, {
id: 3,
name: 'attr 3'
}]
}, {
id: "obj2",
content: [{
id: 4,
name: 'attr 4'
}, {
id: 5,
name: 'attr 5'
}, {
id: 6,
name: 'attr 6'
}]
}, {
id: "obj3",
content: [{
id: 7,
name: 'attr 7'
}, {
id: 8,
name: 'attr 8'
}, {
id: 9,
name: 'attr 9'
}]
}];
I would like to get the object which has the id X in the content array.
I used this ng-repeat:
<ul>
<li ng-repeat="item in myList | filter: {content: [{id:1}]}">
{{item}}
</li>
</ul>
When I use id:1, id:4 or id:7 it works, but not for the other ids...
Has anyone any ideas?
Edit
I FINALLY found out what caused the problem, I was using angular 1.3.0. After upgrading to 1.3.11 it worked!!
You can filter based on nested properties like so:
<li ng-repeat="item in myList | filter: {content: {id: '1'}}">
{{item}}
</li>
It's important to note that the "object" (that has the id X) you'll get will be at the item level.

categorised dropdown select2

i am using select2 multi select dropdown, and it works perfectly but my problem is, i want to categorise the drop down list of the same. Here is my code
<script src="/static/select2.js"></script>
<input type="hidden" id="test" value=""/>
and js
$(test).select2({
data:data,
multiple: true,
width: "100%",
placeholder:"None Selected",
closeOnSelect:false,
});
This should work:
$(test).select2({
data:
[
{
text: 'GREETINGS',
children:
[
{ 'id': 1, text: 'hai' },
{ 'id': 2, text: 'hellow'},
]
},
{
text: 'QUESTIONS',
children:
[
{ 'id': 3, 'text': 'yes' },
{ 'id': 4, 'text': 'no' }
]
}
],
multiple: true,
width: "100%",
placeholder: "None Selected",
closeOnSelect: false,
});

Resources