How to preselect PrimeNG Checkbox items? - html

I am not able to get already selected item. In this code in rp which is an array of type Permission which has one element in it , So basically that value should be selected when I load this div. What will be the mistake?
This is My HTML:-
<div class="gapRowSmall displayFlex flexColumn mb-small" *ngIf="(permissions$ | async)! as permissions">
<div *ngFor="let permission of permissions" class="p-field-checkbox">
<p-checkbox [value]="permission" [(ngModel)]="rp" class=" mr-small"></p-checkbox>
<label>{{permission.name}}</label>
</div>
<div class="displayFlex flexJustifyEnd">
<p-button type="submit" label="Save" styleClass="primary" (onClick)="savePermissions()"
[appSubmitIndicator]="(isSubmitInProgress$ | async)!"></p-button>
</div>
</div>
This is My ts file:-
permissions$ = this.store.select(permissionSelector)
.pipe(takeUntil(this.permissionManagementSubject));
rp: Permission[] = [{ name: 'Create New Transitions', id: 'a45d7806-fbf8-4df7-8248-6f636288ff23' },];

The item in your rp array must completely match one of the items in your Observable permissions array. If not all the fields in the object match, then it will not be selected.
So if the permissions would be loaded in the constructor like this:
constructor() {
this.permissions$ = of([
{name: "aaaaa", id: '123456-789012'},
{name: "bbbbb", id: '223456-789012'},
{name: "ccccc", id: '323456-789012'}
])
}
and the selected permissions in rp would be :
rp: Permission[] = [
{ name: 'aaaaa', id: '123456-789012' },
{ name: 'bbbbb', id: '223456-' }, // This one is incomplete, thus no match
];
Then the second one, will not be selected although partially it is matching.
I've a working example of this in stackblitz. https://stackblitz.com/edit/primeng-checkbox-demo-9rhzru?file=src/app/app.component.ts

Related

Angular 8 Nested Object Interpolation

This is my version of Angular CLI:
Angular CLI: 7.3.9
Node: 12.2.0
OS: win32 x64
Angular: 8.0.2
While making an Angular 8 application, I am trying to use nested FormGroups which correspond to the following object:
const Boilerplate: any = {
1: {
desc: "section1",
content: {
1: "question 1.a:",
2: "question 1.b:",
3: "question 1.c"
}
},
2: {
desc: "section2",
content: {
4: "question 2.a:",
5: "question 2.b:",
6: "question 2.c",
7: "question 2.d"
}
}
}
There is an inner FormGroup of FormControls for section 1 and section 2, and an outer FormGroup holding the two inner formgroups. This is defined in the component.ts.
In the component.html, I am trying to iterate through the outer FormGroup's inner FormGroups, and print the inner FormControls. This is the code I have so far:
<form [formGroup]="sectionGroup">
<div *ngIf="boilerplate">
<div *ngFor="let section of boilerplate | keyvalue">
{{ boilerplate[section.key].desc }}
<div formGroupName="{{section.key}}">
<div *ngFor="let question of boilerplate[{{section.key}}]">
<-- things -->
</div>
</div>
</div>
</div>
The line <div *ngFor="let question of boilerplate[{{section.key}}]"> fails with an error message of:
Unexpected token {, expected identifier, keyword, or string
I have tried the following solutions, none of which have worked for me:
<div *ngFor="let question of {{boilerplate}}.{{section.key}}">
<div *ngFor="let question of {{boilerplate[section.key]}}">
<div *ngFor="let question of {{boilerplate[{{section.key}}]}}">
<td *ngFor="let question of Section">{{boilerplate[[section.key]]}}</td>
I have tried a variety of other {} and [] combinations and orders, and I realize now that nested interpolation is non-parsable.
Does anyone have a suggestion of how I can achieve this? I am using nested FormGroups because it is possible I will have additional layers of sections in the future. The format of the Boilerplate object can be changed if it would make the problem solvable (because I defined it, myself).
EDIT
The following was the solution that resolved this issue:
<div *ngFor="let question of boilerplate[section.key].content | keyvalue">
{{question.value}}
</div>
I try like below,
<div [formGroup]="formGroup">
<div *ngIf="boilerplate">
<div *ngFor="let section of boilerplate | keyvalue">
{{ boilerplate[section.key].desc }}
<div>
<div *ngFor="let question of boilerplate[section.key].content | keyvalue">
{{ question | json }}
</div>
</div>
</div>
Output is like below,
section1
{ "key": "1", "value": "question 1.a:" }
{ "key": "2", "value": "question 1.b:" }
{ "key": "3", "value": "question 1.c" }
section2
{ "key": "4", "value": "question 2.a:" }
{ "key": "5", "value": "question 2.b:" }
{ "key": "6", "value": "question 2.c" }
{ "key": "7", "value": "question 2.d" }
You need to use a keyValue filter pipe then you could just have the following syntax, this will let you use ngFor* to iterate though objects rather than arrays.
<div *ngFor="let question of boilerplate | keyValue">
{{ question.key }} - {{ question.value }}
</div>
You can then do the same for the nested objects inside until you have the correct data displayed. This is not supported in all versions of Angular, but definitely fine in 8.
Where you have Objects with the key as a number, I would look to manipulate that into an array which would help you keep this a little more simple. Allowing you to use traditional *ngFor
The answer from schoolcoder is great, I just would like to post another example for people in the future with the same problem.
I have an object Block that holds a list of Transactions and I want to show it on my page using two *ngFor's
Block model class:
export class Block {
hash: string;
previousBlockHash: string;
transactions: Transaction[]; <<<<<<<<<<<
merkleRoot: string;
tries: number;
timestamp: number;
}
Transaction model class
export class Transaction {
hash: string;
text: string;
senderHash: string;
signature: string;
timestamp: number;
}
How I show it on my page:
Blocks:
<div class="container">
<ul class="list-group">
<li class="list-group-item" *ngFor="let block of blocks | keyvalue">
Hash: {{blocks[block.key].hash}}<br>
Previous block hash: {{blocks[block.key].previousBlockHash}}<br>
Merkle root: {{blocks[block.key].merkleRoot}}<br>
Tries: {{blocks[block.key].tries}}<br>
Timestamp: {{blocks[block.key].timestamp}}<br>
Transactions in this block:
<ul class="list-group">
<li class="list-group-item" *ngFor="let transaction of blocks[block.key].transactions">
{{[block.key]}}<br>
Hash: {{transaction.hash}}<br>
Text: {{transaction.text}}<br>
SenderHash: {{transaction.senderHash}}<br>
Signature: {{transaction.signature}}<br>
Timestamp: {{transaction.timestamp}}
</li>
</ul>
</li>
</ul>
</div>

new retrieved list of the selected item from a list

I have a list which retrieves data from an object from backend, and after selecting an item from that list, it should display its items but i don't know how to render that in html or in rxjs.
Here is my current state after selecting the item Test1 from the list, it retrieve its inner items that are info 1 and info 2.
List:
List: Array(2)
0: {name: "Test1", item: Array(2)}
1: {name: "Test2", item: Array(1)}
length: 2
__proto__: Array(0)
selectedItemData: Array(2)
0: {name: "info 1", item: Array(1)}
1: {name: "info 2", item: Array(4)}
But the list doesn't change, even though everything works concerning the retrieving part of each selected item.
Here is my html :
<ul class="unstyled" *ngFor="let i of (listObservable$|async).list.List">
<li><a (click)="selected(i.name)">{{i.name}}</a></li>
</ul>
When using the async pipe it is best to us an ngIf and map it to a view variable so you only render the element once the observable has emitted.
<ng-container *ngIf="listObservable$ | async as listObj">
<ul class="unstyled" *ngFor="let i of listObj.list.List">
<li><a (click)="selected(i.name)">{{i.name}}</a></li>
</ul>
</ng-container>

angular 2 ngFor Cannot read property of undefined

I have a nested object with data that I am trying to access with ngFor.
I am able to reach the first part of the data with the first ngFor (app_name, time_stamp etc)
But for some reason I am not getting to the nested object of test_cases. When I try it breaks the whole page and the console keeps telling me "Cannot read property 'test_cases' of undefined" and I can't seem to figure out why...
(first part of) data inside the component:
export class AppComponent {
tests = TESTS;
var TESTS: Test[] = [
{
"app_name": "website",
"time_stamp": "2018-01-20T12:00:00Z",
"test_cases": [
{
"test_name": "View article",
"status": true,
}]
}]
HTML partial:
<div id="tested-app" *ngFor = "let item of tests">
<h2>----<span> {{ item.app_name }} </span>----</h2>
<p id="time"> Time: <span> {{item.time_stamp}} </span> </p>
</div>
<div class="module" *ngFor="let subItem of item.test_cases">
<h3>{{subItem.test_name}}</h3>
</div>
For peeps who are struggling with this:
John Montgomery and Andres M answered this in the comments, I had to put the second div inside the first.

Set dynamic id with $index

I've got this code:
My list, wich should work like a navigation with main nav points and sub nav poins:
list = [
{
Id: 1,
Name: 'Main 1',
Items: [
{
Id: 1,
Name: 'Sub 1'
},
{
Id: 2,
Name: 'Sub 2'
}
]
},
{
Id: 2,
Name: 'Main 2',
Items: [
{
Id: 1,
Name: 'Sub 1'
},
{
Id: 2,
Name: 'Sub 2'
}
]
}
];
And this is my HTML. I loop the main poins and it's sub points with ng-repeat and try to set some id's dynamicly with the $index.:
<div class="wrapper" ng-repeat="item in list">
<div id="main_{{$index}}">{{item.Name}}</div>
<div id="main_{{$parent.$index}}_sub_{{$index}}" ng-repeat="sub in item.Items">
<div>— {{sub.Name}}</div>
</div>
</div>
My result is something like this and it works fine:
Main 1
- Sub 1
- Sub 2
Main 2
- Sub 1
- Sub 2
My goal is now to assign a id to my div with the main and my div with the subs. I add the current index with $index to my id in the main div and after that I try to combine the id for the sub divs with the index from the main (it's parent) and the current index. To get the index of the parent, I used $parent.$index. My expected result are follow id's:
Main 1 -> id = main_0
- Sub 1 -> id = main_0_sub_0
- Sub 2 -> id = main_0_sub_1
Main 2 -> id = main_1
- Sub 1 -> id = main_1_sub_0
- Sub 2 -> id = main_1_sub_1
But this doesn't work at the moment. The id's for the main div is correct, but the id for the sub isn't. I thought with $parent.$index it should work, but there is a problem with the current index of the main. I have no idea how to solve this. I hope someone can help me.
Try the below code snippet, it's working fine here !
var app = angular.module('app',[]);
app.controller('Ctrl',function($scope){
$scope.list = [
{
Id: 1,
Name: 'Main 1',
Items: [
{
Id: 1,
Name: 'Sub 1'
},
{
Id: 2,
Name: 'Sub 2'
}
]
},
{
Id: 2,
Name: 'Main 2',
Items: [
{
Id: 1,
Name: 'Sub 1'
},
{
Id: 2,
Name: 'Sub 2'
}
]
}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="Ctrl">
<div class="wrapper" ng-repeat="item in list">
<div id="main_{{$index}}">{{item.Name}} - main_{{$index}}</div>
<div id="main_{{$parent.$index}}_sub_{{$index}}" ng-repeat="sub in item.Items">
<div>— {{sub.Name}} - main_{{$parent.$index}}_sub_{{$index}}</div>
</div>
</div>
</div>
I notice that what you want is have the $index-1. Try this:
<div class="wrapper" ng-repeat="item in list">
<div id="main_{{$index-1}}">{{item.Name}}</div>
<div id="main_{{$parent.$index-1}}_sub_{{$index-1}}" ng-repeat="sub in item.Items>
<div>— {{sub.Name}}</div>
</div>
</div>

Checking for equality in Angular filter

I have objects similar to the ones listed below:
fields = [{id: 1}, {id: 2}, {id: 3}]
rules: [{name: "A", field: {id: 1}}, {name: "B", field: {id: 2}}]
And I want to filter each of the rules out by individual field IDs. Right now I have:
<div ng-repeat="f in fields">
<h4>{{f.id}}</h4>
<li ng-repeat = "rule in rules | filter: {field.id: f.id}">
{{rule.name}}
</li>
</div>
However, the following filter returns no elements. How do I make the filter show the rules that have field.id equal to f.id?
Use this instead:
<div ng-repeat="f in fields">
<h4>{{f.id}}</h4>
<li ng-repeat = "rule in rules | filter:{ field: {id: f.id} }">
{{rule.name}}
</li>
</div>
Match the object structure in the filter.
Here is the demo where I have added another property age (int) to prove the fact that filter only works on id.