How to set template reference dynamically inside function - javascript

I have a function below from which I am calling setModelData.
My query is I want to make template variable dynamic for both getGlobalList and getNonGlobalList function.
For Example
1) if getGlobalList is running it will set template: this.CustomTableItemTemplate
inside the setModelData function.
2) if getNonGlobalList is running it will pass template: this.NonGlobalCustomTableItemTemplate
inside the setModelData function.
Thanks for help
Code
#ViewChild('CustomTableItemTemplate') CustomTableItemTemplate: TemplateRef<any>;
#ViewChild('NonGlobalCustomTableItemTemplate') NonGlobalCustomTableItemTemplate: TemplateRef<any>;
ngOnInit() {
this.getGlobalList();
this.getNonGlobalList();
}
getGlobalList() {
this.globalSchemamodel.data.length = 0;
this.Service.getGlobalList(
this.constructQueryParam(this.globalSchemamodel, 'global'))
.subscribe((response: any) => {
const globalSchemas = response ? response.data : [];
if (globalSchemas.records) {
this.setModelData(globalSchemas, this.globalSchemamodel);
}
});
}
getNonGlobalList() {
this.nonGlobalSchemamodel.data.length = 0;
this.Service.getList(
this.constructQueryParam(this.nonGlobalSchemamodel, 'nonglobal'))
.subscribe((response: any) => {
const nonglobalschemaslist = response ? response.data : [];
if (nonglobalschemaslist.records) {
this.setModelData(nonglobalschemaslist, this.nonGlobalSchemamodel);
}
});
}
setModelData(globalSchemas, globalSchemamodel) {
for (const schema of globalSchemas.records) {
const tableModel = [
new TableItem({ data: schema.schema_id }),
this.isAdminRole ? new TableItem({
data:[{ 'schemaId': schema.schema_id }],
**template: this.CustomTableItemTemplate**
}) : null
];
globalSchemamodel.data.push(tableModel);
}
}

setModelData function needs another template param that's for sure.
Additionally you can extract similar code from getNonGlobalList and getGlobalList
ngOnInit() {
this.getList(
this.globalSchemamodel,
this.Service.getGlobalList,
'global',
this.CustomTableItemTemplate
);
this.getList(
this.nonGlobalSchemamodel,
this.Service.getList',
'nonglobal',
this.NonGlobalCustomTableItemTemplate
);
}
getList(model: any, functionToCall: any, paramName: string, template: TemplateRef<any>) {
model.data.length = 0;
functionToCall(
this.constructQueryParam(model, paramName))
.subscribe((response: any) => {
const schemas = response ? response.data : [];
if (schemas.records) {
this.setModelData(schemas.records, model);
}
});
}
setModelData(schemas: any[], schemaModel: any, template: TemplateRef<any>) {
for (const { schema_id } of schemas) {
const tableModel = [
new TableItem({
data: schema_id
}),
this.isAdminRole ? new TableItem({
data: [
{
'schemaId': schema_id
}
],
template
}) : null
];
schemaModel.data.push(tableModel);
}
}

Related

How to access JSON object value with dynamic key in typescript with angular

I want to access value present in JSON object with configurable targetPath for response received.
Below is my component class which will bind the data present in list to the autocomplete drop down in HTML code
the configurable key is 'path', which value I want to provide as a key in custom JSON object key 'field'.
import { Component, ViewChild } from '#angular/core';
import { MenuItem } from 'primeng/api';
import { SelectItem } from 'primeng/api';
import { SelectItemGroup } from 'primeng/api';
import { FilterService } from 'primeng/api';
import { AutoComplete } from 'primeng/autocomplete';
import { CountryService } from './countryservice';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
providers: [CountryService, FilterService]
})
export class AppComponent {
userDetails: any[];
selectedUserDetails: any[];
selectedValue: any;
selectedUserDetail: any;
path: string = 'contactMedium[0].characteristic.emailAddress';
testVal: string;
constructor() {}
ngOnInit() {
this.userDetails = [
{
id: 'cont-609',
contactMedium: [
{
characteristic: {
emailAddress: 'test#gmail.com'
}
}
]
},
{
id: 'cont-610',
contactMedium: [
{
characteristic: {
emailAddress: 'test#gmail.com'
}
}
]
},
{
id: 'cont-611',
contactMedium: [
{
characteristic: {
emailAddress: 'test#gmail.com'
}
}
]
},
{
id: 'cont-612',
contactMedium: [
{
characteristic: {
emailAddress: 'test#gmail.com'
}
}
]
},
{
id: 'cont-614',
contactMedium: [
{
characteristic: {
emailAddress: 'test#gmail.com'
}
}
]
}
];
}
filterUserDetails(event) {
const filteredNew: any[] = [];
this.getUserDetails().then(response => {
for (let resp of response) {
this.testVal = resp[this.path];
filteredNew.push({
id: resp.id,
field: resp[this.path]
});
}
});
this.selectedUserDetails = filteredNew;
}
getUserDetails(): Promise<any[]> {
return Promise.resolve(this.userDetails);
}
chooseItem(event) {
this.selectedUserDetail =
event.contactMedium[0].characteristic.emailAddress;
}
}
From the response received from method getUserDetails(), I am building a custom JSON object array with fields 'id' and 'field', the key for id is known which itself is a 'id' but key for field is configurable which is path in my case.
But looks like above logic where key is accessed is not working as expected i.e I am not getting value for
filterUserDetails(event) {
const filteredNew: any[] = [];
this.getUserDetails().then(response => {
for (let resp of response) {
this.testVal = resp[this.path];
filteredNew.push({
id: resp.id,
field: resp[this.path]
});
}
});
this.selectedUserDetails = filteredNew;
}
Below is my HTML code
<h5>Dropdown Testing</h5>
<p>selectedUserDetail : {{selectedUserDetail}}</p>
<p>TestVal : {{testVal}}</p>
<p-autoComplete [(ngModel)]="selectedUserDetail" [suggestions]="selectedUserDetails"
(completeMethod)="filterUserDetails($event)" [dropdown]="true" field="field">
<ng-template let-userDetails pTemplate=" item">
<div>{{userDetails.field}}</div>
</ng-template>
</p-autoComplete>
If I change the usage of assignment like below everything works fine
field: resp.contactMedium[0].characteristic.emailAddress
Link of my code is here : https://stackblitz.com/edit/primeng-autocomplete-demo-dyihrs?file=src%2Fapp%2Fapp.component.html
Expectation here is to assign value of key: contactMedium[0].characteristic.emailAddress received from getUserDetails() to custom JSON object which is getting build in filterUserDetails() to 'field' key.
You should be aware that your field can be very complex but in the case you mentioned, can be resolved with this:
resolveField(data: any, field: string): any {
if (data && field) {
let fields: string[] = field.split('.');
let value = data;
for(let i = 0, len = fields.length; i < len; ++i) {
if (value == null) {
return null;
} else {
const pos: number = fields[i].match(/\d+/g)?.[0];
if(pos != null) {
const property = fields[i].match(/^\w+/g);
value = value[property][pos];
} else {
value = value[fields[i]];
}
}
}
return value;
} else {
return null;
}
}
You can use the resolveField function as part of your logic. You can modify it, as you want or required, for example: here is considering only letters as part of the property names.
Here is the solution for your code.
You can use a variable that has the dynamic key
var obj = {
...
}
var key = ...;
obj[key] = somevalue;
or to get the value
var somevalue = obj[key];

Get bad values inside a loop

I've got a method for generate url
But I have a little problem when I'm adding the condition if/else, he returns me only the first value and not all
This is my code :
public generateUrl(components: any, versions: any) {
const keys: any[] = Object.keys(components); //['toto','titi','tata','tutu']
for (const component of keys) {
const versions = components[component].artifacts.map((arti) => {
return {
component: arti.name,
type: arti.type,
version: versions[arti.name],
};
});
console.log(versions); // Display only the first one and not all
//[ { component: 'toto',
// type: 'npm',
// version: '1' } ]
for (const i in versions) {
const v = versions[i];
// here i'm adding the confition
if (v.type === "jar") {
const urlTest =
v.component +
"/" +
v.version +
".jar"
return urlTest;
} else if (v.type === "npm") {
const urlTest =
v.component +
"/" +
v.version +
".npm"
return urlTest;
}
} else if (v.type === "rpm") {
const urlTest =
v.component +
"/" +
v.version +
".rpm"
return urlTest;
}
}
}
}
}
I need to retrieve all values and not only the first one.
THanks for your help
Use Array.prototype.reduce to accumulate your values which match up to your type, instead of returning after match.
Also the for-in loop is to enumerate over enumerable object properties of a object, if I am not mistaken then versions is an array.
Working example below -
const data = [
{
component: 'toto',
type: 'npm',
version: '1'
},
{
component: 'tata',
type: 'jar',
version: '2'
},
{
component: 'titi',
type: 'rpm',
version: '3'
}
];
const types = ['npm', 'jar', 'rpm'];
const testUrls = data.reduce((acc, { component, type, version }) => {
if (types.includes(type)) {
acc.push(`${component}/${version}.${type}`);
}
return acc;
}, []);
console.log(testUrls);
like #Bergi said
That's because you return from the first iteration of the loop.
else you can try something like that, by using reduce:
Working example:
type Component = {
artifacts: any[];
};
type Version = {
[key: string]: string;
}
class Test {
public static GenerateUrl(components: Component[], versions: Version) {
return components.reduce((acc: any, { artifacts }) => {
return artifacts.reduce((acc, { type, name }) => {
acc.push(`${name}#${versions[name]}.${type}`);
return acc.flat();
}, acc);
}, []);
}
};
const versions: any = {
"titi": "1.0.0",
"toto": "1.8.1",
"tata": "1.2.5"
}
const components = [
{
artifacts: [
{
type: "jar",
name: "titi"
},
{
type: "npm",
name: "titi"
},
{
type: "rpm",
name: "toto"
},
{
type: "rpm",
name: "tata"
}
]
}
]
console.log(Test.GenerateUrl(components, versions)); // ["titi#1.0.0.jar","titi#1.0.0.npm","toto#1.8.1.rpm","tata#1.2.5.rpm"]

RxJs BehaviorSubject for Array that allow setting/subscribing to individual items

I would like to use a BehaviorSubject to store an Array of objects and have a way to easily update (next?) a single item of that array without having to update the whole array.
I would also like for an easy way to subscribe to changes to an specific item of that array. I know it could be done with filter, but an easier way would be nice...
Is that possible?
I am currently using this version I created (which I don't know if it is the best way or not) that also persists its contents to localstorage:
export class LocalStorageBehaviorSubject<T, Y = T> {
private _data: BehaviorSubject<T>;
public asObservable() {
return this._data.asObservable();
}
public next(data: T) {
if(this.expirationFn !== null) {
data = this.expirationFn(data);
}
localStorage.setItem(this.key, JSON.stringify(data));
this._data.next(data);
}
public nextItem(item: Y) {
if (!Array.isArray(this._data.getValue())) {
throw "Type is not an Array";
}
let dados: any = (<any>this._data.getValue()).slice();
if (dados.some(r => r[this.id] === item[this.id])) {
dados = dados.map(r => r[this.id] === item[this.id] ? item : r);
} else {
dados.push(item);
}
if(this.expirationFn !== null) {
dados = this.expirationFn(dados);
}
localStorage.setItem(this.key, JSON.stringify(dados));
this._data.next(<any>dados);
}
public removeItem(id) {
if (!Array.isArray(this._data.getValue())) {
throw "Type is not an Array";
}
let dados: any = (<any>this._data.getValue()).slice();
dados = dados.filter(r => r[this.id] !== id);
localStorage.setItem(this.key, JSON.stringify(dados));
this._data.next(<any>dados);
}
public removeExpiredData(){
let data = this.loadFromStorage();
if (data) {
if(this.expirationFn !== null) {
data = this.expirationFn(data);
}
this._data.next(data);
}
}
public getValue() {
this.removeExpiredData();
return this._data.getValue();
}
public getItem(id): Y {
if (!Array.isArray(this._data.getValue())) {
throw "Type is not an Array";
}
this.removeExpiredData();
return (<any>this._data.getValue()).slice().find(t => t[this.id] == id);
}
constructor(private key: string, private id: string, defaultValue: any = null, private expirationFn: (dados: T) => T = null) {
this._data = new BehaviorSubject<T>(defaultValue);
this.removeExpiredData();
}
private loadFromStorage(): T {
let dadosStr = localStorage.getItem(this.key);
if (dadosStr) {
return JSON.parse(dadosStr);
}
return null;
}
}
I hoped that would be an simpler way...
Thanks
I would also like for an easy way to subscribe to changes to an
specific item of that array. I know it could be done with filter, but
an easier way would be nice...
You can use map operator and inside lambda array.find
Example
const mockStorage = {
values: {},
setItem(key, value) {
this.values[key] = value;
},
getItem(key) {
return this.values[key]
},
clearItem(key) {
this.values[key] = undefined;
}
}
class LocalStorageBehaviorSubject {
constructor(key, defaultValue) {
this.key = key;
this._data = new rxjs.BehaviorSubject(defaultValue);
}
nextItem(item) {
const list = this._data.value;
const itemIndex = list.findIndex(pr => pr.id === item.id);
this._data.next([
...list.slice(0, itemIndex),
{
...(list[itemIndex] || {}),
...item
},
...list.slice(itemIndex + 1)
]);
}
removeItem(id) {
this._data.next(this._data.value.filter(pr => pr.id !== id));
}
getItem(id) {
return this.asObservable()
.pipe(
rxjs.operators.map(values => values.find(pr => pr.id === id) || null),
rxjs.operators.distinctUntilChanged());
}
asObservable() {
return this._data.asObservable().pipe(
rxjs.operators.tap(values => {
if (values && values.length) {
mockStorage.setItem(this.key, JSON.stringify(values));
}
else {
mockStorage.clearItem(this.key);
}
}))
}
}
const localStorageBehaviorSubject = new LocalStorageBehaviorSubject('items', []);
localStorageBehaviorSubject
.getItem(1)
.subscribe(item => {
console.log(item);
})
localStorageBehaviorSubject.nextItem({id: 1, value: 'test'})
localStorageBehaviorSubject.nextItem({id: 1, value: 'test1'})
localStorageBehaviorSubject.nextItem({id: 2, value: 'test2'})
localStorageBehaviorSubject.nextItem({id: 3, value: 'test3'})
localStorageBehaviorSubject.removeItem(2);
localStorageBehaviorSubject.removeItem(1);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.js"></script>

How to dispatch a Vue computed property

I´m trying to dispatch an object which is created in a computed.
I can´t get it to work as I´m fairly new to vue.js
I want to dispatch the object "updateObject" to the vuex-store.
Tried with setters but didn´t work. I think if I can set the "varia" object to the same object like "updateObject" then I could maybe dispatch it?
Hope somebody can help me.
Here is my code:
<template>
<div class="detail">
<b-row align-v="center"><b-button variant="success" #click="submit()">submit</b-button></b-row>
// some more code...
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
data () {
return {
subID: '',
res: '',
showAlert: true,
varia: null
}
},
computed: {
...mapState([
'FA',
'Main',
'Sub',
'layouttype'
]),
getVariable: function (Sub, layouttype) {
const subID = this.layouttype.sub_id
var filterObj = this.Sub.filter(function (e) {
return e.sub_id === subID
})
console.log(filterObj)
return filterObj
},
updateObject: {
// getterfunction
get: function () {
var len = this.getVariable.length
var res = []
for (var i = 0; i < len; i++) {
if (i in this.getVariable) {
var val = this.getVariable[i].variable
res.push(val)
}
}
console.log(res)
var ergebnis = {}
res.forEach(key => {
if (this.FA[key]) {
ergebnis[key] = this.FA[key]
}
})
return ergebnis
},
// setterfunction
set: function (value) {
this.varia = value
}
}
},
methods: {
submit () {
this.$store.dispatch('sendData', this.ergebnis)
}
}
}
</script>
It tell´s me "this.ergebnis" is undefined
You can try it declaring "ergebnis" as global variable under data as
export default {
data () {
return {
subID: '',
res: '',
showAlert: true,
varia: null,
ergebnis : {}
}
},
computed: {
...mapState([
'FA',
'Main',
'Sub',
'layouttype'
]),
getVariable: function (Sub, layouttype) {
const subID = this.layouttype.sub_id
var filterObj = this.Sub.filter(function (e) {
return e.sub_id === subID
})
console.log(filterObj)
return filterObj
},
updateObject: {
// getterfunction
get: function () {
var len = this.getVariable.length
var res = []
for (var i = 0; i < len; i++) {
if (i in this.getVariable) {
var val = this.getVariable[i].variable
res.push(val)
}
}
console.log(res)
res.forEach(key => {
if (this.FA[key]) {
this.ergebnis[key] = this.FA[key]
}
})
return this.ergebnis
},
// setterfunction
set: function (value) {
this.varia = value
}
}
},
methods: {
submit () {
this.$store.dispatch('sendData', this.ergebnis)
}
}
}
Now ergebnis is accessible

not show items in tree angular material 9

i want to show items in Tree Items in angular 9 and angular material .
my problem is here :
i want to show 3 or 4 level in tree . i send a request to server and get flat item , and i need to convert that to multi level model .
intialData(): any {
this.searchParam.page = 1;
this.searchParam.rows = 1000;
this.claimsManagerService.getAll(this.searchParam).subscribe(data => {
data['records'].forEach(element => {
let model = {} as FileNode;
if (element.parentId == null) {
model.id = element.id;
model.isChilde = element.isChilde;
model.parentId = element.parentId;
model.title = element.title;
data['records'].forEach(child => {
if (child.parentId == element.id) {
let childe = {} as FileNode;
childe.id = child.id;
childe.isChilde = child.isChilde;
childe.parentId = child.parentId;
childe.title = child.title;
if (!model.children) model.children = [] as FileNode[];
model.children.push(childe)
data['records'].forEach(childs => {
if (childs.parentId === child.id) {
let childe = {} as TreeNode;
childe.id = childs.id;
childe.isChilde = childs.isChilde;
childe.parentId = child.parentId;
childe.title = child.title;
let item = model.children.find(x => x.id == childs.parentId);
if (!item.children) item.children = [] as TreeNode[];
item.children.push(childe);
}
})
}
})
this.dataSource.data.push(model)
}
})
return this.dataSource.data
})
}
i write this code for show data in tree :
export interface FileNode {
id: number;
title: string;
parentId: number;
isChilde: boolean;
children?: FileNode[];
}
export interface TreeNode {
id: number;
title: string;
parentId: number;
isChilde: boolean;
level: number;
expandable: boolean;
}
#Component({
selector: 'kt-role-tree',
templateUrl: './tree.component.html',
styleUrls: ['./tree.component.css'],
providers: [TreeBuilder]
})
export class TreeComponent implements OnInit,AfterViewInit {
#Output() selectedList = new EventEmitter<any>();
/** The TreeControl controls the expand/collapse state of tree nodes. */
treeControl: FlatTreeControl<TreeNode>;
treeFlattener: MatTreeFlattener<FileNode, TreeNode>;
searchParam: TableSearch;
dataSource: MatTreeFlatDataSource<FileNode, TreeNode>;
treeModel :object;
constructor(private database: TreeBuilder,
private claimsManagerService: ClaimsManagerService,
private cdRef: ChangeDetectorRef,
private dialog: MatDialog) {
this.treeFlattener = new MatTreeFlattener(
this.transformer,
this.getLevel,
this.isExpandable,
this.getChildren);
this.searchParam = {
_search: true,
dateTimeType: 1,
page: 1,
rows: 2
};
this.treeControl = new FlatTreeControl<TreeNode>(this.getLevel, this.isExpandable);
this.dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);
this.intialData();
}
ngAfterViewInit(): void {
this.cdRef.detectChanges();
}
ngOnInit(): void {
}
/** Transform the data to something the tree can read. */
transformer(node: FileNode, level: number) {
return {
id: node.id,
title: node.title,
parentId: node.parentId,
isChilde: node.isChilde,
level: level,
expandable: !!node.children
};
}
/** Get the level of the node */
getLevel(node: TreeNode) {
return node.level;
}
/** Return whether the node is expanded or not. */
isExpandable(node: TreeNode) {
return node.expandable;
};
/** Get the children for the node. */
getChildren(node: FileNode) {
return observableOf(node.children);
}
/** Get whether the node has children or not. */
hasChild(node: TreeNode) {
return node.expandable;
}
delete(id: number): void {
const title = 'Post Delete';
const itemName = `Post `;
const service = this.claimsManagerService;
const dialogRef = this.dialog.open(DeleteEntityDialogComponent, {
data: { id, title, itemName, service },
width: '440px'
});
dialogRef.afterClosed().subscribe(res => {
if (res) {
this.intialData();
}
});
}
openAdd(id, title): void {
let dialogRef;
if (typeof (id) === 'string') {
dialogRef = this.dialog.open(ClaimsManagerAddComponent, {
data: { id: null, isChilde: false, claimName: 'Main' }
});
} else {
dialogRef = this.dialog.open(ClaimsManagerAddComponent, {
data: { id: id, isChilde: true, claimName: title }
});
}
dialogRef.afterClosed().subscribe(() => {
this.intialData();
})
}
intialData(): any {
this.searchParam.page = 1;
this.searchParam.rows = 1000;
this.claimsManagerService.getAll(this.searchParam).subscribe(data => {
data['records'].forEach(element => {
let model = {} as FileNode;
if (element.parentId == null) {
model.id = element.id;
model.isChilde = element.isChilde;
model.parentId = element.parentId;
model.title = element.title;
data['records'].forEach(child => {
if (child.parentId == element.id) {
let childe = {} as FileNode;
childe.id = child.id;
childe.isChilde = child.isChilde;
childe.parentId = child.parentId;
childe.title = child.title;
if (!model.children) model.children = [] as FileNode[];
model.children.push(childe)
data['records'].forEach(childs => {
if (childs.parentId === child.id) {
let childe = {} as TreeNode;
childe.id = childs.id;
childe.isChilde = childs.isChilde;
childe.parentId = child.parentId;
childe.title = child.title;
let item = model.children.find(x => x.id == childs.parentId);
if (!item.children) item.children = [] as TreeNode[];
item.children.push(childe);
}
})
}
})
this.dataSource.data.push(model)
}
})
return this.dataSource.data
})
}
}
and this is the html code :
<mat-tree [dataSource]="dataSource" [treeControl]="treeControl">
<mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle matTreeNodePadding>
<button mat-icon-button disabled></button>
{{node.title}}
</mat-tree-node>
<mat-tree-node *matTreeNodeDef="let node;when: hasChild" matTreeNodePadding>
<button mat-icon-button matTreeNodeToggle
[attr.aria-label]="'toggle ' + node.title">
<mat-icon class="mat-icon-rtl-mirror">
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
{{node.title}} {{node.id}}
</mat-tree-node>
but it not show me any things in html .
whats the problem ? how can i solve this problem ????

Categories

Resources