UI: Refactoring LwM2M

This commit is contained in:
Vladyslav_Prykhodko 2021-01-26 19:20:36 +02:00
parent f770f40797
commit c14e2c81b1
4 changed files with 94 additions and 129 deletions

View File

@ -82,7 +82,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
private deviceProfileService: DeviceProfileService, private deviceProfileService: DeviceProfileService,
@Inject(WINDOW) private window: Window) { @Inject(WINDOW) private window: Window) {
this.lwm2mDeviceProfileFormGroup = this.fb.group({ this.lwm2mDeviceProfileFormGroup = this.fb.group({
objectIds: [[], Validators.required], objectIds: [null, Validators.required],
observeAttrTelemetry: [null, Validators.required], observeAttrTelemetry: [null, Validators.required],
shortId: [null, Validators.required], shortId: [null, Validators.required],
lifetime: [null, Validators.required], lifetime: [null, Validators.required],
@ -96,15 +96,10 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
configurationJson: [null, Validators.required] configurationJson: [null, Validators.required]
}); });
this.lwm2mDeviceProfileFormGroup.valueChanges.subscribe((value) => { this.lwm2mDeviceProfileFormGroup.valueChanges.subscribe((value) => {
if (!this.disabled) { this.updateDeviceProfileValue(value);
this.updateDeviceProfileValue(value);
}
}); });
this.lwm2mDeviceConfigFormGroup.valueChanges.subscribe(() => { this.lwm2mDeviceConfigFormGroup.valueChanges.subscribe(() => {
console.warn('config form'); this.updateModel();
if (!this.disabled) {
this.updateModel();
}
}); });
this.sortFunction = this.sortObjectKeyPathJson; this.sortFunction = this.sortObjectKeyPathJson;
} }
@ -188,7 +183,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
private updateDeviceProfileValue(config): void { private updateDeviceProfileValue(config): void {
if (this.lwm2mDeviceProfileFormGroup.valid) { if (this.lwm2mDeviceProfileFormGroup.valid) {
this.upDateObserveAttrTelemetryFromGroupToJson(config.observeAttrTelemetry.clientLwM2M); this.updateObserveAttrTelemetryFromGroupToJson(config.observeAttrTelemetry.clientLwM2M);
this.configurationValue.bootstrap.bootstrapServer = config.bootstrapServer; this.configurationValue.bootstrap.bootstrapServer = config.bootstrapServer;
this.configurationValue.bootstrap.lwm2mServer = config.lwm2mServer; this.configurationValue.bootstrap.lwm2mServer = config.lwm2mServer;
const bootstrapServers = this.configurationValue.bootstrap.servers; const bootstrapServers = this.configurationValue.bootstrap.servers;
@ -225,9 +220,6 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
this.updateKeyNameObjects(keyNameJson, clientObserveAttrTelemetry); this.updateKeyNameObjects(keyNameJson, clientObserveAttrTelemetry);
} }
} }
clientObserveAttrTelemetry.forEach(obj => {
obj.instances.sort((a, b) => a.id - b.id);
});
return {clientLwM2M: clientObserveAttrTelemetry}; return {clientLwM2M: clientObserveAttrTelemetry};
} }
@ -239,8 +231,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
private addInstances = (attribute: string[], telemetry: string[], clientObserveAttrTelemetry: ObjectLwM2M[]): void => { private addInstances = (attribute: string[], telemetry: string[], clientObserveAttrTelemetry: ObjectLwM2M[]): void => {
const instancesPath = attribute.concat(telemetry) const instancesPath = attribute.concat(telemetry)
.filter(instance => !instance.includes('/0/')) .filter(instance => !instance.includes('/0/'))
.map(instance => this.convertPathToInstance(instance)) .map(instance => instance.slice(1, instance.lastIndexOf('/')))
.sort(); .sort(this.sortPath);
new Set(instancesPath).forEach(path => { new Set(instancesPath).forEach(path => {
const pathParameter = Array.from(path.split('/'), Number); const pathParameter = Array.from(path.split('/'), Number);
@ -253,24 +245,14 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
}); });
} }
private convertPathToInstance = (path: string): string => {
const [objectId, instanceId] = path.substring(1).split('/');
return `${objectId}/${instanceId}`;
}
private updateObserveAttrTelemetryObjects = (parameters: string[], clientObserveAttrTelemetry: ObjectLwM2M[], private updateObserveAttrTelemetryObjects = (parameters: string[], clientObserveAttrTelemetry: ObjectLwM2M[],
nameParameter: string): void => { nameParameter: string): void => {
parameters.forEach(parameter => { parameters.forEach(parameter => {
const [objectId, instanceId, resourceId] = Array.from(parameter.substring(1).split('/'), Number); const [objectId, instanceId, resourceId] = Array.from(parameter.substring(1).split('/'), Number);
clientObserveAttrTelemetry clientObserveAttrTelemetry.find(objectLwm2m => objectLwm2m.id === objectId)
.forEach(key => { .instances.find(itrInstance => itrInstance.id === instanceId)
if (key.id === objectId) { .resources.find(resource => resource.id === resourceId)
const instance = key.instances.find(itrInstance => itrInstance.id === instanceId); [nameParameter] = true;
if (isDefinedAndNotNull(instance)) {
instance.resources.find(resource => resource.id === resourceId)[nameParameter] = true;
}
}
});
}); });
} }
@ -278,62 +260,60 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
const keyName = JSON.parse(JSON.stringify(nameJson)); const keyName = JSON.parse(JSON.stringify(nameJson));
Object.keys(keyName).forEach(key => { Object.keys(keyName).forEach(key => {
const [objectId, instanceId, resourceId] = Array.from(key.substring(1).split('/'), Number); const [objectId, instanceId, resourceId] = Array.from(key.substring(1).split('/'), Number);
clientObserveAttrTelemetry clientObserveAttrTelemetry.find(objectLwm2m => objectLwm2m.id === objectId)
.forEach(object => { .instances.find(instance => instance.id === instanceId)
if (object.id === objectId) { .resources.find(resource => resource.id === resourceId)
object.instances .keyName = keyName[key];
.find(instance => instance.id === instanceId).resources
.find(resource => resource.id === resourceId).keyName = keyName[key];
}
});
}); });
} }
private upDateObserveAttrTelemetryFromGroupToJson = (val: ObjectLwM2M[]): void => { private updateObserveAttrTelemetryFromGroupToJson = (val: ObjectLwM2M[]): void => {
const observeArray: Array<string> = []; const observeArray: Array<string> = [];
const attributeArray: Array<string> = []; const attributeArray: Array<string> = [];
const telemetryArray: Array<string> = []; const telemetryArray: Array<string> = [];
const observeJson: ObjectLwM2M[] = JSON.parse(JSON.stringify(val)); const observeJson: ObjectLwM2M[] = JSON.parse(JSON.stringify(val));
const paths = new Set<string>();
let pathObj; let pathObj;
let pathInst; let pathInst;
let pathRes; let pathRes;
observeJson.forEach(obj => { observeJson.forEach(obj => {
Object.entries(obj).forEach(([key, value]) => { for (const [key, value] of Object.entries(obj)) {
if (key === 'id') { if (key === 'id') {
pathObj = value; pathObj = value;
} }
if (key === 'instances') { if (key === 'instances') {
const instancesJson = JSON.parse(JSON.stringify(value)) as Instance[]; const instancesJson = value as Instance[];
if (instancesJson.length > 0) { if (instancesJson.length > 0) {
instancesJson.forEach(instance => { instancesJson.forEach(instance => {
Object.entries(instance).forEach(([instanceKey, instanceValue]) => { for (const [instanceKey, instanceValue] of Object.entries(instance)) {
if (instanceKey === 'id') { if (instanceKey === 'id') {
pathInst = instanceValue; pathInst = instanceValue;
} }
if (instanceKey === 'resources') { if (instanceKey === 'resources') {
const resourcesJson = JSON.parse(JSON.stringify(instanceValue)) as ResourceLwM2M[]; const resourcesJson = instanceValue as ResourceLwM2M[];
if (resourcesJson.length > 0) { if (resourcesJson.length > 0) {
resourcesJson.forEach(res => { resourcesJson.forEach(res => {
Object.entries(res).forEach(([resourceKey, resourceValue]) => { for (const [resourceKey, idResource] of Object.entries(res)) {
if (resourceKey === 'id') { if (resourceKey === 'id') {
// pathRes = resourceValue pathRes = `/${pathObj}/${pathInst}/${idResource}`;
pathRes = '/' + pathObj + '/' + pathInst + '/' + resourceValue; } else if (resourceKey === 'observe' && idResource) {
} else if (resourceKey === 'observe' && resourceValue) {
observeArray.push(pathRes); observeArray.push(pathRes);
} else if (resourceKey === 'attribute' && resourceValue) { } else if (resourceKey === 'attribute' && idResource) {
attributeArray.push(pathRes); attributeArray.push(pathRes);
} else if (resourceKey === 'telemetry' && resourceValue) { paths.add(pathRes);
} else if (resourceKey === 'telemetry' && idResource) {
telemetryArray.push(pathRes); telemetryArray.push(pathRes);
paths.add(pathRes);
} }
}); }
}); });
} }
} }
}); }
}); });
} }
} }
}); }
}); });
if (isUndefined(this.configurationValue[this.observeAttr])) { if (isUndefined(this.configurationValue[this.observeAttr])) {
this.configurationValue[this.observeAttr] = { this.configurationValue[this.observeAttr] = {
@ -346,7 +326,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
this.configurationValue[this.observeAttr][this.attribute] = attributeArray; this.configurationValue[this.observeAttr][this.attribute] = attributeArray;
this.configurationValue[this.observeAttr][this.telemetry] = telemetryArray; this.configurationValue[this.observeAttr][this.telemetry] = telemetryArray;
} }
this.updateKeyName(); this.updateKeyName(paths);
} }
sortObjectKeyPathJson = (key: string, value: object): object => { sortObjectKeyPathJson = (key: string, value: object): object => {
@ -366,23 +346,13 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
} }
private sortPath = (a, b): number => { private sortPath = (a, b): number => {
const aLC = Array.from(a.substring(1).split('/'), Number); return a.localeCompare(b, undefined, {
const bLC = Array.from(b.substring(1).split('/'), Number); numeric: true,
return aLC[0] === bLC[0] ? aLC[1] - bLC[1] : aLC[0] - bLC[0]; sensitivity: 'base'
});
} }
private updateKeyName = (): void => { private updateKeyName = (paths: Set<string>): void => {
const paths = new Set<string>();
if (this.configurationValue[this.observeAttr][this.attribute]) {
this.configurationValue[this.observeAttr][this.attribute].forEach(path => {
paths.add(path);
});
}
if (this.configurationValue[this.observeAttr][this.telemetry]) {
this.configurationValue[this.observeAttr][this.telemetry].forEach(path => {
paths.add(path);
});
}
const keyNameNew = {}; const keyNameNew = {};
paths.forEach(path => { paths.forEach(path => {
const pathParameter = this.findIndexesForIds(path); const pathParameter = this.findIndexesForIds(path);
@ -395,19 +365,19 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
} }
private findIndexesForIds = (path: string): number[] => { private findIndexesForIds = (path: string): number[] => {
const pathParameter = Array.from(path.substring(1).split('/'), Number); const [objectId, instanceId, resourceId] = Array.from(path.substring(1).split('/'), Number);
// TODO: All paths to map
const pathParameterIndexes: number[] = []; const pathParameterIndexes: number[] = [];
const objectsOld = deepClone( const objectsOld = this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').value.clientLwM2M as ObjectLwM2M[];
this.lwm2mDeviceProfileFormGroup.get('observeAttrTelemetry').value.clientLwM2M) as ObjectLwM2M[]; let isIdIndex = (element) => element.id === objectId;
let isIdIndex = (element) => element.id === pathParameter[0];
const objIndex = objectsOld.findIndex(isIdIndex); const objIndex = objectsOld.findIndex(isIdIndex);
if (objIndex >= 0) { if (objIndex >= 0) {
pathParameterIndexes.push(objIndex); pathParameterIndexes.push(objIndex);
isIdIndex = (element) => element.id === pathParameter[1]; isIdIndex = (element) => element.id === instanceId;
const instIndex = objectsOld[objIndex].instances.findIndex(isIdIndex); const instIndex = objectsOld[objIndex].instances.findIndex(isIdIndex);
if (instIndex >= 0) { if (instIndex >= 0) {
pathParameterIndexes.push(instIndex); pathParameterIndexes.push(instIndex);
isIdIndex = (element) => element.id === pathParameter[2]; isIdIndex = (element) => element.id === resourceId;
const resIndex = objectsOld[objIndex].instances[instIndex].resources.findIndex(isIdIndex); const resIndex = objectsOld[objIndex].instances[instIndex].resources.findIndex(isIdIndex);
if (resIndex >= 0) { if (resIndex >= 0) {
pathParameterIndexes.push(resIndex); pathParameterIndexes.push(resIndex);
@ -456,16 +426,16 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
if (index >= 0) { if (index >= 0) {
objectsOld.splice(index, 1); objectsOld.splice(index, 1);
} }
this.updateObserveAttrTelemetryObjectFormGroup(objectsOld);
this.removeObserveAttrTelemetryFromJson(this.observe, value.id); this.removeObserveAttrTelemetryFromJson(this.observe, value.id);
this.removeObserveAttrTelemetryFromJson(this.telemetry, value.id); this.removeObserveAttrTelemetryFromJson(this.telemetry, value.id);
this.removeObserveAttrTelemetryFromJson(this.attribute, value.id); this.removeObserveAttrTelemetryFromJson(this.attribute, value.id);
this.removeKeyNameFromJson(value.id); this.removeKeyNameFromJson(value.id);
this.updateObserveAttrTelemetryObjectFormGroup(objectsOld);
this.upDateJsonAllConfig(); this.upDateJsonAllConfig();
} }
private removeObserveAttrTelemetryFromJson = (observeAttrTel: string, id: number): void => { private removeObserveAttrTelemetryFromJson = (observeAttrTel: string, id: number): void => {
const isIdIndex = (element: string) => element.startsWith(`/${id}`); const isIdIndex = (element) => element.startsWith(`/${id}`);
let index = this.configurationValue[this.observeAttr][observeAttrTel].findIndex(isIdIndex); let index = this.configurationValue[this.observeAttr][observeAttrTel].findIndex(isIdIndex);
while (index >= 0) { while (index >= 0) {
this.configurationValue[this.observeAttr][observeAttrTel].splice(index, 1); this.configurationValue[this.observeAttr][observeAttrTel].splice(index, 1);

View File

@ -19,18 +19,17 @@ import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Valida
import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { Observable, of } from 'rxjs'; import { Observable } from 'rxjs';
import { filter, map, mergeMap, tap } from 'rxjs/operators'; import { filter, map, mergeMap, publishReplay, refCount, tap } from 'rxjs/operators';
import { ObjectLwM2M } from './profile-config.models'; import { ObjectLwM2M } from './profile-config.models';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { DeviceProfileService } from '@core/http/device-profile.service'; import { DeviceProfileService } from '@core/http/device-profile.service';
import { Direction } from '@shared/models/page/sort-order'; import { Direction } from '@shared/models/page/sort-order';
import { isDefined, isDefinedAndNotNull, isEmptyStr } from '@core/utils'; import { isDefined, isDefinedAndNotNull, isEmptyStr, isString } from '@core/utils';
@Component({ @Component({
selector: 'tb-profile-lwm2m-object-list', selector: 'tb-profile-lwm2m-object-list',
templateUrl: './lwm2m-object-list.component.html', templateUrl: './lwm2m-object-list.component.html',
styleUrls: [],
providers: [ providers: [
{ {
provide: NG_VALUE_ACCESSOR, provide: NG_VALUE_ACCESSOR,
@ -42,10 +41,10 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
private requiredValue: boolean; private requiredValue: boolean;
private dirty = false; private dirty = false;
private allObjectsList: Observable<Array<ObjectLwM2M>>; private lw2mModels: Observable<Array<ObjectLwM2M>>;
private modelValue: Array<number> = [];
lwm2mListFormGroup: FormGroup; lwm2mListFormGroup: FormGroup;
modelValue: Array<number> | null;
objectsList: Array<ObjectLwM2M> = []; objectsList: Array<ObjectLwM2M> = [];
filteredObjectsList: Observable<Array<ObjectLwM2M>>; filteredObjectsList: Observable<Array<ObjectLwM2M>>;
disabled = false; disabled = false;
@ -57,11 +56,8 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
@Input() @Input()
set required(value: boolean) { set required(value: boolean) {
const newVal = coerceBooleanProperty(value); this.requiredValue = coerceBooleanProperty(value);
if (this.requiredValue !== newVal) { this.updateValidators();
this.requiredValue = newVal;
this.updateValidators();
}
} }
@Output() @Output()
@ -73,7 +69,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
@ViewChild('objectInput') objectInput: ElementRef<HTMLInputElement>; @ViewChild('objectInput') objectInput: ElementRef<HTMLInputElement>;
private propagateChange = (v: any) => { private propagateChange = (v: any) => {
}; }
constructor(private store: Store<AppState>, constructor(private store: Store<AppState>,
public translate: TranslateService, public translate: TranslateService,
@ -81,7 +77,7 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
private fb: FormBuilder) { private fb: FormBuilder) {
this.lwm2mListFormGroup = this.fb.group({ this.lwm2mListFormGroup = this.fb.group({
objectsList: [this.objectsList], objectsList: [this.objectsList],
objectLwm2m: [null, this.required ? [Validators.required] : []] objectLwm2m: ['']
}); });
} }
@ -104,11 +100,10 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
if (value && typeof value !== 'string') { if (value && typeof value !== 'string') {
this.add(value); this.add(value);
} else if (value === null) { } else if (value === null) {
this.clear(this.objectInput.nativeElement.value); this.clear();
} }
}), }),
filter((value) => typeof value === 'string'), filter(searchText => isString(searchText)),
// map(value => value ? value : ''),
mergeMap(searchText => this.fetchListObjects(searchText)) mergeMap(searchText => this.fetchListObjects(searchText))
); );
} }
@ -127,23 +122,21 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
writeValue(value: any): void { writeValue(value: any): void {
this.searchText = ''; this.searchText = '';
const objectIds = 'objectIds'; if (isDefinedAndNotNull(value)) {
if (value.hasOwnProperty(objectIds) && value[objectIds] != null && value[objectIds].length > 0) { if (Array.isArray(value.objectIds)) {
this.modelValue = [...value[objectIds]]; this.modelValue = value.objectIds;
this.objectsList = value.objectsList; this.objectsList = value.objectsList;
} else { } else {
this.objectsList = []; this.objectsList = [];
this.modelValue = null; this.modelValue = [];
}
this.lwm2mListFormGroup.get('objectsList').setValue(this.objectsList, {emitEvents: false});
this.dirty = false;
} }
this.lwm2mListFormGroup.get('objectsList').setValue(this.objectsList);
this.dirty = true;
} }
private add(object: ObjectLwM2M): void { private add(object: ObjectLwM2M): void {
if (!this.modelValue || this.modelValue.indexOf(object.id) === -1) { if (this.modelValue.indexOf(object.id) === -1) {
if (!this.modelValue) {
this.modelValue = [];
}
this.modelValue.push(object.id); this.modelValue.push(object.id);
this.objectsList.push(object); this.objectsList.push(object);
this.lwm2mListFormGroup.get('objectsList').setValue(this.objectsList); this.lwm2mListFormGroup.get('objectsList').setValue(this.objectsList);
@ -176,41 +169,42 @@ export class Lwm2mObjectListComponent implements ControlValueAccessor, OnInit, V
const filters = {names: [], ids: []}; const filters = {names: [], ids: []};
if (isDefinedAndNotNull(searchText) && !isEmptyStr(searchText)) { if (isDefinedAndNotNull(searchText) && !isEmptyStr(searchText)) {
const ids = searchText.match(/\d+/g); const ids = searchText.match(/\d+/g);
filters.ids = isDefinedAndNotNull(ids) ? ids.map(Number) as [] : filters.ids; filters.ids = ids !== null ? ids.map(Number) : filters.ids;
const names = searchText.trim().split(" ") as []; filters.names = searchText.trim().toUpperCase().split(' ');
filters.names = names;
} }
const predicate = objectLwM2M => filters.names.filter(word => objectLwM2M.name.toUpperCase().includes(word.toUpperCase())).length>0 const predicate = objectLwM2M => filters.names.find(word => objectLwM2M.name.toUpperCase().includes(word))
|| filters.ids.includes(objectLwM2M.id); || filters.ids.includes(objectLwM2M.id);
return this.getListModels().pipe( return this.getLwM2mModels().pipe(
map(objectLwM2Ms => searchText ? objectLwM2Ms.filter(predicate) : objectLwM2Ms) map(objectLwM2Ms => searchText ? objectLwM2Ms.filter(predicate) : objectLwM2Ms)
); );
} }
private getListModels(): Observable<Array<ObjectLwM2M>> { private getLwM2mModels(): Observable<Array<ObjectLwM2M>> {
if (!this.allObjectsList) { if (!this.lw2mModels) {
const sortOrder = { const sortOrder = {
property: 'name', property: 'name',
direction: Direction.ASC direction: Direction.ASC
}; };
this.allObjectsList = this.deviceProfileService.getLwm2mObjects(sortOrder, null, null).pipe( this.lw2mModels = this.deviceProfileService.getLwm2mObjects(sortOrder).pipe(
mergeMap(objectsList => of(objectsList)) publishReplay(1),
refCount()
); );
} }
return this.allObjectsList; return this.lw2mModels;
} }
onFocus = (): void => { onFocus = (): void => {
if (this.dirty) { if (!this.dirty) {
this.lwm2mListFormGroup.get('objectLwm2m').updateValueAndValidity({onlySelf: true, emitEvent: true}); this.lwm2mListFormGroup.get('objectLwm2m').updateValueAndValidity({onlySelf: true, emitEvent: true});
this.dirty = false; this.dirty = true;
} }
} }
private clear = (value: string = ''): void => { private clear = (value: string = ''): void => {
this.objectInput.nativeElement.value = value; this.objectInput.nativeElement.value = value;
this.lwm2mListFormGroup.get('objectLwm2m').patchValue(value, {emitEvent: true}); this.searchText = '';
this.lwm2mListFormGroup.get('objectLwm2m').patchValue(value);
setTimeout(() => { setTimeout(() => {
this.objectInput.nativeElement.blur(); this.objectInput.nativeElement.blur();
this.objectInput.nativeElement.focus(); this.objectInput.nativeElement.focus();

View File

@ -16,23 +16,24 @@
--> -->
<section [formGroup]="observeAttrTelemetryFormGroup" class="mat-padding"> <section [formGroup]="observeAttrTelemetryFormGroup">
<mat-accordion multi="true" class="mat-body-1" formArrayName="clientLwM2M"> <mat-accordion multi="true" class="mat-body-1" formArrayName="clientLwM2M">
<mat-expansion-panel <mat-expansion-panel
*ngFor="let objectLwM2M of clientLwM2MFormArray.controls; let i = index; trackBy: trackByParams" *ngFor="let objectLwM2M of clientLwM2MFormArray.controls; let i = index;"
[formGroupName]="i"> [formGroupName]="i">
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title fxLayoutAlign="space-between"> <mat-panel-title fxLayoutAlign="start center">
<div class="tb-panel-title"><b><i>{{ objectLwM2M.get('name').value}}</i></b> (object [<b>{{ objectLwM2M.get('id').value}}</b>])</div> <b><i>{{ objectLwM2M.get('name').value}}</i></b>&nbsp;&lt;id: {{ objectLwM2M.get('id').value}}>
<button type="button"
*ngIf="!disabled"
[fxShow]="objectLwM2M.get('multiple').value"
mat-button mat-icon-button (click)="addInstances($event, objectLwM2M.value)"
matTooltip="{{'device-profile.lwm2m.add-instances-tip' | translate}}"
matTooltipPosition="above">
<mat-icon class="material-icons">{{'add'}}</mat-icon>
</button>
</mat-panel-title> </mat-panel-title>
<mat-panel-description fxLayoutAlign="end center" *ngIf="!disabled">
<button type="button"
[fxShow]="objectLwM2M.get('multiple').value"
mat-button mat-icon-button (click)="addInstances($event, objectLwM2M.value)"
matTooltip="{{'device-profile.lwm2m.add-instances-tip' | translate}}"
matTooltipPosition="above">
<mat-icon class="material-icons">{{'add'}}</mat-icon>
</button>
</mat-panel-description>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<ng-template matExpansionPanelContent> <ng-template matExpansionPanelContent>
<div fxLayout="column" fxLayoutGap="8px" formArrayName="instances"> <div fxLayout="column" fxLayoutGap="8px" formArrayName="instances">

View File

@ -176,7 +176,7 @@ export class Lwm2mObserveAttrTelemetryComponent implements ControlValueAccessor
this.observeAttrTelemetryFormGroup.get('clientLwM2M').updateValueAndValidity(); this.observeAttrTelemetryFormGroup.get('clientLwM2M').updateValueAndValidity();
} }
trackByParams = (index: number): number => { trackByParams = (index: number, element: any): number => {
return index; return index;
} }