#Input data binding not rendering to the child using Highcharts api - html

When I triggered an event coming from a method via an input it don't render properly the data to the chart here's an example of my pb:
My chart was working until I put it in the child. It looks like the data are not coming trough the child.
parent.html:
<div class="parent" >
<img src="black.png" type="button" (click)="displayChild()"/>
<my-child [displayDetail]="displayMe"></my-child>
</div>
parent.ts:
displayChild() {
this.displayMe = !this.displayMe;
child.html:
<div class="chart-pie">
<chart [options]="options" (load)="saveInstance($event.context)"
</chart>
</div>
child.ts:
#Input() displayDetail: boolean;
options: any;
data: Object[];
chart: any;
dataSubscription: Subscription;
constructor(private userService3: UserService3) {
this.options = {
chart: { type: 'pie',
series: [{
name: 'Dispo',
data: []
}]
};
saveInstance(chartInstance) {
this.chart = chartInstance;
console.log(chartInstance);
}
public ngOnInit () {
this.dataSubscription =
this.userService3.getData().subscribe((data) => {
this.options.series[0].data = data.data.operating_rate;
// Code for the pie
let percentUp = data.data.operating_rate; // 88.14
let percentDown = 100 - percentUp; // 11.86
this.options.series[0].data = [
{
name: 'Up',
y: percentUp,
color: '#648e59'
},
{
name: 'Down',
y: percentDown,
color: 'white'
}
];
console.log(data);
});
}
public ngOnDestroy() {
if (this.dataSubscription) {
this.dataSubscription.unsubscribe();
}
}
}

Related

Pass data from parent component to child component using input, how to implement?

There is a parent component with all the logic of the chart, you need to transfer data to the child component using #Input (), that is, so that I can display the chart in any of the components using #Input.
The parent component is logs.component and the child component is echarts.component. It is necessary to pass the data to LoadEcharts(), it contains all the logic of the Chart, that is, that I could call it on any html component
logs.components.ts
export class LogsComponent implements OnInit {
sideNavStatus: boolean = false;
subscription!: Subscription;
logs!: Logs[];
constructor(private dataService: DataService) {
}
columnDefs = [
{ headerName: 'Username', field: 'username', flex: 1},
{ headerName: 'Event', field: 'event', flex: 1 },
{ headerName: 'Date', field: 'date', flex: 1 }
];
ngOnInit() {
this.LoadLogs();
this.LoadEcharts();
}
LoadLogs(): void {
this.dataService.getLogs().subscribe(logs => this.logs = logs);
}
LoadEcharts(): void {
const chartDom: HTMLElement = document.getElementById('main') as HTMLElement;
const myChart = echarts.init(chartDom);
this.subscription = this.dataService.getLogs().subscribe(data => {
myChart.setOption(this.initBasicEchart(data))
})
}
private initBasicEchart(data: Logs[]) {
const result: any = {};
data.forEach(el => {
const date = el.date.toString().substring(0, 10);
if (!result[el.event]) {
result[el.event] = {};
if (!result[el.event][date]) {
result[el.event][date] = 1;
}
} else {
if (!result[el.event][date]) {
result[el.event][date] = 1;
} else {
result[el.event][date] += 1;
}
}
});
const login = {
x: Object.keys(result.Login),
y: Object.values(result.Login)};
const reg = {
c: Object.keys(result.Registration),
z: Object.values(result.Registration)};
return {
title: {
text: 'Graphic login and registration.'
},
tooltip: {},
xAxis: {
type: 'category',
data: (reg.c, login.x)
},
yAxis: {
},
series: [
{
name: 'Login',
type: 'bar',
data: login.y,
},
{
name: 'Registration',
type: 'bar',
data: reg.z,
}
]
};
}
}
logs.component.html
<div class="container-fluid g-0">
<app-header (sideNavToggled)="sideNavStatus = $event;"></app-header>
<main>
<app-sidebar [sideNavStatus]="sideNavStatus"
[ngClass]="{'app-side-nav-open': sideNavStatus}"></app-sidebar>
<div class="display-area p-3" [ngClass]="{'display-area-shrink': sideNavStatus}">
<p class="fs-1 fw-bold fst-italic text-center">Login and registration statistics.
</p>
<app-aggreed
*ngIf="logs"
[logs]="logs"
[columnDefs]="columnDefs"
></app-aggreed>
</div>
</main>
</div>
<app-echarts
></app-echarts>
<app-footer></app-footer>
echarts.component.html
<div class="container-fluid g-0">
<app-header (sideNavToggled)="sideNavStatus = $event;"></app-header>
<main>
<app-sidebar [sideNavStatus]="sideNavStatus"
[ngClass]="{'app-side-nav-open': sideNavStatus}"></app-sidebar>
<div class="display-area p-3" [ngClass]="{'display-area-shrink': sideNavStatus}">
<div
id="main"
style="width: 500px; height: 300px"
>
</div >
</div>
</main>
</div>
<app-footer></app-footer>
export class EchartsComponent implements OnInit {
sideNavStatus: boolean = false;
subscription!: Subscription;
constructor(private dataService: DataService) {
}
ngOnInit(): void {
}
}
I tried to pass methods to the child component through the input but nothing comes out
From your code sample, I'm assuming you're trying to access the EchartsComponent ViewChild in the logs component and pass data to it.
Here's an example of how you can do that, minus some pieces from your sample code for brevity...
class LogsComponent {
#ViewChild(EchartsComponent)
echartsComponent: EchartsComponent;
LoadEcharts(): void {
const chartDom: HTMLElement = document.getElementById('main') as HTMLElement; // <-- not sure what this is
const myChart = echarts.init(chartDom); // <-- not sure what this is
this.subscription = this.dataService.getLogs().subscribe(data => {
this.echartsComponent.logs = data;
// `logs` doesn't exist in the current code for EchartsComponent.
// You'll need to add it.
});
}
}
What I don't see in your EchartsComponent is a logs property to set. If you're using a ViewChild in the parent component, you don't have to use #Input on the ViewChild instance, you have programmatic access to the component and can set properties or call methods.
If you want to use #Input(), you can do that too:
class EchartsComponent {
#Input()
logs: Logs[];
}
// logs.component.ts
class LogsComponent {
LoadEcharts(): void {
this.subscription = this.dataService.getLogs().subscribe(data => {
this.logs = data;
})
}
}
// logs.component.html
<app-echarts [logs]="logs"></app-echarts>
In this scenario, when the observable for getLogs() emits, the property logs is set to the new value. That value, being a new reference is passed to the child component via its input.
Hope that helps you out.

Can't set my tab to default on ngOnInIt when displaying

So I done some changes to my code however i could be blind sighted, however when adding the ngoninit to the typescript file, and adding a value in it, my default tab disappeared. Not sure what i done wrongly be nice for someone to have a look. I have tried a few things, but can't see anything that stand out. Please see code attached.
Typescript Code:
export class OptionsComponent extends DynamicLoaderComponent<BaseOptionsTabComponent> implements OnDestroy {
childComponents = new Map(new IterableObject({
[OptionsTab.customDays]: {
component: CustomDaysComponent,
data: {},
name: 'Options_CustomDays',
tooltip: 'Options_CustomDays'
},
[OptionsTab.customFields]: {
component: EditCustomFieldsComponent,
data: {},
name: 'Options_CustomFields',
tooltip: 'Options_CustomFields'
},
[OptionsTab.backup]: {
component: OptionsBackupComponent,
data: {},
name: 'Options_Backup',
tooltip: 'Options_Backup'
},
[OptionsTab.system]: {
component: OptionsSystemComponent,
data: {},
name: 'Options_System',
tooltip: 'Options_SystemTime'
},
[OptionsTab.email]: {
component: OptionsEmailComponent,
data: {},
name: 'Options_Email',
tooltip: 'Options_Email'
},
[OptionsTab.dataProtection]: {
component: DmsDataProtectionComponent,
data: {},
name: 'Options_DataProtection',
tooltip: 'Options_DataProtection'
},
[OptionsTab.about]: {
component: OptionsAboutComponent,
data: this.startAppInformationService.upgradeData,
name: 'UpperRibbon_About',
tooltip: 'UpperRibbon_About'
}
}));
private subscriber: Subscriber<void>;
private observable = new Observable<void>(s => this.subscriber = s);
private keyImport = [ OptionsTab.importData ];
private import = {
component: OptionsImportComponent,
data: {},
name: 'Options_Import',
tooltip: 'Options_Import',
isHidden: () => !dmsSettings.permissions.isAllowedToEdit(Entity.roots.people)
};
constructor (
componentFactoryResolver: ComponentFactoryResolver,
private startAppInformationService: StartAppInformationService
) {
super(componentFactoryResolver);
}
ngOnInit () {
if (dmsSettings.importTabOption) {
this.childComponents.set(this.keyImport, this.import);
}
}
ngOnDestroy () {
this.subscriber && this.subscriber.unsubscribe();
}
setComponentData<U extends BaseOptionsTabComponent> (component: U, child: ChildComponentInterface<U>) {
super.setComponentData(component, child);
component.observable = this.observable;
}
setActiveTab (tab: string) {
this.loadComponent(tab);
}
isOptionsInReadMode () {
return dmsSettings.permissions.isOptionsAccessLevelRead();
}
isActiveTab (tab: string) {
return this.currentChildComponent === tab;
}
save () {
this.subscriber.next();
}
}
HTML code:
<header class="modal-header">
<h6 class="ondrag" attr.data-qa-id="{{ 'Options_Title' | localize }}">{{ 'Options_Title' | localize }}</h6>
<button type="button" class="close close-modal"></button>
<ul class="tabs">
<li *ngFor="let keyValuePair of childComponents | keyValueMap"
(click)="setActiveTab(keyValuePair.key)"
[hidden]="keyValuePair.value.isHidden && keyValuePair.value.isHidden()"
[gui-tooltip]="keyValuePair.value.tooltip"
[ngClass]="{'active': isActiveTab(keyValuePair.key)}"
attr.data-name="{{ keyValuePair.value.name | localize}}"
attr.data-qa-id="{{ keyValuePair.value.name | localize}}">
{{ keyValuePair.value.name | localize}}
</li>
</ul>

Dynamic id with canvas on html and angular

i want to set a dynamic id for my report (canvas) in my html with angular but im getting an error if u can help me pls, this is the code of my class and my html
export class CardKPIReporteComponent implements OnInit {
#BlockUI() blockUI: NgBlockUI;
#Input() datos_kpi_reporte: any
fetcher: any
arrayListaKpis: any
tituloreporte: any
id: any = 1
chartBienesUbicacion: any;
constructor(private procesoOperacionService: ProcesoOperacionesService
) {
}
ngOnInit() {
this.tituloreporte = this.datos_kpi_reporte.servicio_nombre
this.id = this.datos_kpi_reporte.cont //this.id = 1
this.Grafico2();
}
Grafico2() {
// this.id = this.datos_kpi_reporte.cont
var nombrechart = "Reporte" + this.datos_kpi_reporte.cont
this.chartBienesUbicacion = new Chart(nombrechart, {
type: 'pie',
data: {
labels: ['ENTREGADO', 'NO ENTREGADO', '1', '1'],
datasets: [
{
label: 'Cantidad',
data: ['1', '1', '1', '1'], // this.chartsTotal,
backgroundColor: 'rgba(54, 162, 235, 0.2)',
borderColor:
'rgba(54, 162, 235, 1)',
borderWidth: 1
}
]
},
options: {
title: {
text: nombrechart,
display: true
},
scales: {
yAxes: [
{
ticks: {
beginAtZero: true
}
}
]
}
}
});
}
}
<mat-card-content>
<!--<app-alert></app-alert> -->
<div class="row">
<canvas id="Reporte{{ this.id }}"></canvas>
</div>
</mat-card-content>
ive been trying this way but im getting this error: "Chart.js:8459 Failed to create chart: can't acquire context from the given item"
This is happening because your trying to add the canvas before you set the id in the template. You need to set the ID in the template, and after the view initializes then add your chart.
make sure you implement AfterViewInit and update your code as such.
ngOnInit() {
this.tituloreporte = this.datos_kpi_reporte.servicio_nombre
this.id = this.datos_kpi_reporte.cont
}
ngAfterViewInit() {
this.Grafico2();
}

angular ngx-treeview from Json object error : A text of item must be string object

this treeview item text is confusing me for the past week
this is how I load the items into the tree view:
ngOnInit(): void {
this.items = this.getItems([JSON.stringify(this.json_obj)]);
}
getItems(parentChildObj: any[]) {
let itemsArray: TreeviewItem[] = [];
parentChildObj.forEach((set: TreeItem) => {
itemsArray.push(new TreeviewItem(set,true))
});
return itemsArray;
}
and this is how I create the nested Json object from non-nested Json file :
this.departments.forEach(element => {
if(element.ParentID == 0){
p_counter++;
this.json_obj.push(
{
text: element.DepartmentName ,
value: 'p'+p_counter.toString() ,
children: [],
id: element.DepartmentID.toString() ,
} as never
);
element.DepartmentName = 'fixed';
}
});
the template is simple as that:
<ngx-treeview [items]="items" dir ="rtl"></ngx-treeview>
btw- it creates a perfect nesting but it cant read the object properties in
new TreeviewItem(set,true);
because it's undefined.
Error : A text of item must be string object at new TreeviewItem
please help me figure this out, what can I do to make it work?
You have used
text: element.DepartmentName ,
value: 'p'+p_counter.toString() ,
children: [],
id: element.DepartmentID.toString()
It seems you have not followed TreeItem interface given in treeview-item.d.ts
export interface TreeItem {
text: string;
value: any;
disabled?: boolean;
checked?: boolean;
collapsed?: boolean;
children?: TreeItem[];
}
you should remove id because that is not property of TreeItem interface.
import { Component,OnInit } from '#angular/core';
import { TreeviewItem } from 'ngx-treeview';
#Component({
selector: 'my-app',
template: `<ngx-treeview [items]="items"></ngx-treeview>`
})
export class AppComponent implements OnInit {
items: TreeviewItem[];
ngOnInit() {
this.items = this.getItems();
}
getItems(){
// fetch api response
// convert response into this format (object can be nested, should contain below keys only with given type)
// {
// text: string;
// value: any;
// disabled ?: boolean;
// checked ?: boolean;
// collapsed ?: boolean;
// children ?: TreeItem[];
// }
const item = new TreeviewItem({
text: 'Children', value: 1, children: [
{ text: 'Baby 3-5', value: 11 },
{ text: 'Baby 6-8', value: 12 },
{ text: 'Baby 9-12', value: 13 }
]
});
return [ item ];
}
}
stackblitz example

Angular refresh data in child component from filtered value

I have a reusable child table component that loads dynamically based on data from the parent component.
For the first time everything loads well, however when I need to click on one of the sort columns in the table I need to send that sort property again to the parent component to return the result from api and refresh the data in the child component with a new set of data from api.
In the code it looks like this, I missed something in that refresh:
table.component.ts
export class TableComponent implements OnChanges {
#Input() items;
#Input() headers;
#Input('sortColumn') sortColumn;
#Output() sortColumnChange = new EventEmitter<string>();
ngOnChanges(changes: SimpleChanges) {
this.items;
console.log('OnChanges', changes);
}
onSortClick(event, selectedColumn) {
const target = event.currentTarget,
classList = target.classList;
let column = '';
if (classList.contains('sort-icon-asc')) {
classList.remove('sort-icon-asc');
classList.add('sort-icon-desc');
column = `${selectedColumn} DESC`;
this.sortColumn = column;
this.sortColumnChange.emit(column);
} else {
classList.add('sort-icon-asc');
classList.remove('sort-icon-desc');
column = `${selectedColumn} ASC`;
this.sortColumn = column;
this.sortColumnChange.emit(column);
}
}
}
table.component.html
<table>
<thead>
<td (click)="onSortClick($event, header.value)" *ngFor="let header of headers" class="sort-icon-asc">{{ header.name }}</td>
</thead>
<tbody>
<tr *ngFor="let item of items">
<td *ngFor="let value of item | objectValues">
{{ value }}
</td>
</tr>
</tbody>
</table>
users.component.ts
export class UsersComponent implements OnInit {
observablesDispose$: Subject<void> = new Subject();
sortColumn = 'userId ASC';
items: [];
usersTableHeaders = [
{
value: 'userId',
name: this.translateService.instant('ADMIN.USERS_TABLE.USER_ID')
},
{
value: 'name',
name: this.translateService.instant('ADMIN.USERS_TABLE.NAME')
},
{
value: 'role',
name: this.translateService.instant('ADMIN.USERS_TABLE.ROLE')
},
{
value: 'email',
name: this.translateService.instant('ADMIN.USERS_TABLE.EMAIL')
},
{
value: 'status',
name: this.translateService.instant('ADMIN.USERS_TABLE.STATUS')
}
];
constructor(
private readonly usersService: UsersService,
private readonly translateService: TranslateService
) {}
ngOnInit(): void {
this.getUsers();
}
getUsers(): void {
this.usersService
.getUsers(this.sortColumn)
.pipe(takeUntil(this.observablesDispose$))
.subscribe((users) => {
this.items = users.resultList.map((tableColumn) => ({
userId: tableColumn.userId,
name: tableColumn.displayName,
role: tableColumn.role,
email: tableColumn.email,
status: tableColumn.status
}));
});
}
ngOnDestroy(): void {
this.observablesDispose$.next();
this.observablesDispose$.complete();
}
}
users.component.html
<div class="row">
<div class="table-section">
<app-table
[headers]="usersTableHeaders"
[items]="items"
[(sortColumn)]="sortColumn">
</app-table>
</div>
</div>
EDIT
users.component.ts
export class UsersComponent implements OnInit {
observablesDispose$: Subject<void> = new Subject();
sortColumn = 'userId ASC';
items: [];
usersTableHeaders = [
{
value: 'userId',
name: this.translateService.instant('ADMIN.USERS_TABLE.USER_ID')
},
{
value: 'name',
name: this.translateService.instant('ADMIN.USERS_TABLE.NAME')
},
{
value: 'role',
name: this.translateService.instant('ADMIN.USERS_TABLE.ROLE')
},
{
value: 'email',
name: this.translateService.instant('ADMIN.USERS_TABLE.EMAIL')
},
{
value: 'status',
name: this.translateService.instant('ADMIN.USERS_TABLE.STATUS')
}
];
constructor(
private readonly usersService: UsersService,
private readonly translateService: TranslateService
) {}
ngOnInit(): void {
this.getUsers();
}
getUsers(): void {
this.usersService
.getUsers(this.sortColumn)
.pipe(takeUntil(this.observablesDispose$))
.subscribe((users) => {
this.items = users.resultList.map((tableColumn) => ({
userId: tableColumn.userId,
name: tableColumn.displayName,
role: tableColumn.role,
email: tableColumn.email,
status: tableColumn.status
}));
});
}
updateSort(newColumn: string): void {
this.sortColumn = newColumn;
this.getUsers();
}
ngOnDestroy(): void {
this.observablesDispose$.next();
this.observablesDispose$.complete();
}
}
users.component.html
<div class="row">
<div class="table-section">
<app-table
[headers]="usersTableHeaders"
[items]="items"
[(sortColumn)]="sortColumn"
(sortColumnChange)="updateSort($event)"
>
</app-table>
</div>
</div>
In your way of handle sortColumn change you cannot control change of it to update users list. In your component you should do like:
users.component.html
<div class="row">
<div class="table-section">
<app-table
[headers]="usersTableHeaders"
[items]="items"
[sortColumn]="sortColumn"
(sortColumnChange)="updateSort($event)">
</app-table>
</div>
</div>
users.component.ts
...
updateSort(newColumn: string): void {
this.sortColumn = newColumn;
getUsers();
}