How to loop over an array of objects and display it in UI using angular 8 - angular8

I am trying to loop over an array of objects and display it in html using Angular 8.
My app.component.ts file is as shown below:
In the above code uptimeDataSet is the array of data that I need to loop over and display on another component.
My app.component.html file looks as shown below:
Finally, I am trying to loop over in my component to display the object in uptime-chart-component.html as below:
But I am not able to get the details in the UI. I am not able to find out where I am going wrong. Can someone please help me with this.

Update your uptime-chart.component.ts file-
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-uptime-chart',
templateUrl: './uptime-chart.component.html',
styleUrls: ['./uptime-chart.component.css']
})
export class UptimeChartComponent implements OnInit {
#Input() chartData: any[];
constructor() { }
ngOnInit(): void {
}
}
You need use #Input to capture the value in your child component. #Input decorator is used when you are passing data from parent to child. I suggest you take a look at this blog to understand- https://fireship.io/lessons/sharing-data-between-angular-components-four-methods/
And I believe, you can change your app.component.html without the *ngFor-
<app-user [chartData]="uptimeDataSet"></app-user>
if this is what you want your result to be

Related

How to pass data from one child to parent and other child components?

I have divided my page into following format. I have a parent component and multiple child components. First one being the filter component. So when I make a submit in this component its result is to be implemented in all other child component as well as in parent component too.
I think of as the date I receive from child-A to parent component pass it to child-B and child-C but I couldn't fix it.
I am working here:
https://stackblitz.com/edit/angular-fqp5px
Can anybody help me on this?
Thank You.
You can just create simple service and pass value to Subject object. And subscribe that object in other component where ever you want to make use of it.
For example service:
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/of';
import { Subject } from 'rxjs';
#Injectable()
export class dataService {
//here i am giving example for string. You can use any kind of object(class)
private querySource = new Subject<string>();
query$ = this.querySource.asObservable();
functionname(value: string){
this.querySource.next(value);
}
}
Now subscribe this service and call functionName function on submit button. And the change will be subscribed where ever you want it in parent or any other child component.
For refrence go through this

Angular input change detection performance with mat table data source

Does anyone know if updating a mat table data source in the ngOnChanges lifecycle hook is ok? Or is there a potential data leak or performance concern at scale?
Here is a simple example of what I mean.
A child component has a parent component that inputs data, like so:
<data-list [data]="someData"></data-list>
and the child component:
import { Component, Input, SimpleChanges, OnInit, OnChanges } from '#angular/core';
import { MatTableDataSource } from '#angular/material';
#Component({
selector: 'data-list',
templateUrl: './data-list.component.html',
styleUrls: ['./data-list.component.scss']
})
export class DataListComponent implements OnInit, OnChanges {
#Input() data: any[];
dataSource: MatTableDataSource<any>;
displayedColumns = [
'title',
'detail'
];
constructor() { }
ngOnInit() {
this.dataSource = new MatTableDataSource<any>(this.data);
}
ngOnChanges(changes: SimpleChanges) {
this.dataSource = new MatTableDataSource<any>(changes.data.currentValue);
}
}
Now the parent component is subscribed to different observables that react to different changes to the data. That is, if data is added or removed, the parent component is updated accordingly which it passes along as an input into the child component.
And since the child component is using the ngOnChanges lifecycle hook to watch for changes in the input data, the child component updates the table data by instantiating a new MatTableDataSource.
Everything works just dandy. Except that the ngOnChanges fires often and I'm wary to instantiate a new table source every single time -- as in, it makes me nervous.
I know that this child component could just subscribe to the changes and be in charge of the data rather than receive it from a parent component, but I would rather keep the "smart" and "dumb" component relationship if I can.
Is anyone doing things this way at scale or in production? Is this ok? Am I just being neurotic because I've been staring at my computer screen for the better half of the last 24 hours?

Aurelia - call function on nested component

I want to call a child component's function from its parent. I have a way to do it, but I want to know if I'm missing a better way.
From Ashley Grant's blog post about accessing a custom element's viewModel from a custom attribute, I see that Aurelia adds au to the element and you can access the viewModel through that. So, if I add a nested component with a ref, like this:
<template>
<nested-element ref="childElement"></nested-element>
</template>
I can call a function on it like this:
this.childElement.au.controller.viewModel.someFunction();
This feels roundabout. I was hoping I would be able to access a nested element's viewModel through the parameters to a hook that the parent implements, such as created(owningView, myView) but I can't find a path to it.
Have I missed a better way?
Edit: I forgot to add that I need a return value from the function I'm calling, so having access to the viewmodel itself is preferable
ref gives you the element. view-model.ref gives you the element's view model.
<template>
<nested-element view-model.ref="childViewModel"></nested-element>
</template>
Call it like this in the parent view-model:
this.childViewModel.someFunction();
If you only have one instance of the nested-element or don't care if multiple nested-elements respond to the event. Then you could use standard Javascript event functionality for this:
bar.html
<template>
<h1>${value}</h1>
<input type="text" value.bind="value"></input>
<foo>text</foo>
</template>
bar.ts
import {bindable} from 'aurelia-framework';
export class Bar {
#bindable value;
public valueChanged(newValue, oldValue) {
var event = new CustomEvent("some-event-name", { "detail": { message: "Hello from Bar", oldValue, newValue } });
document.dispatchEvent(event);
}
}
foo.html
<template>
<h1>${value}</h1>
</template>
foo.ts
import {bindable} from 'aurelia-framework';
export class Foo {
constructor() {
document.addEventListener("some-event-name", (e) => {
console.log('hello here is Foo, recieved event from Bar : ', e);
}, true);
}
}

Getting element height

I was curious if I can get element properties form component template.
So I have made simple div with class and I've made this class:
export class viewApp{
elementView: any;
viewHeight: number;
myDOM: Object;
constructor() {
this.myDOM = new BrowserDomAdapter();
}
clickMe(){
this.elementView = this.myDOM.query('div.view-main-screen');
this.viewHeight = this.myDOM.getStyle(this.elementView, 'height');
}
}
getStyle(), query() are from BrowserDomAdapter.
My problem is when I try to get height it is null, but when I set some height by setStyle() and then I get it by getStyle() it returns proper value.
After checking DOM and styles in browser I discovered that is because of two CSS elements. One is: .view-main-screen[_ngcontent-aer-1]{} and second one is element{}.
.view-main-screen has some stylings, but element is empty. When I add styles by setStyle() it appears in element{}. Why is that? How can I get element properties by using Angular2?
The correct way is to use #ViewChild() decorator:
https://angular.io/docs/ts/latest/api/core/index/ViewChild-decorator.html
Template:
<div class="view-main-screen" #mainScreen></div>
Component:
import { ElementRef, ViewChild } from '#angular/core';
export class viewApp{
#ViewChild('mainScreen') elementView: ElementRef;
viewHeight: number;
constructor() {
}
clickMe(){
this.viewHeight = this.elementView.nativeElement.offsetHeight;
}
}
That should do it but obviously you need to add your Component decorator.
Edit:
For Angular 8 or later you need to provide the 2nd parameter in ViewChild
#ViewChild('mainScreen', {read: ElementRef, static:false}) elementView: ElementRef;
update2
constructor(private elementRef:ElementRef) {}
someMethod() {
console.log(this.elementRef.nativeElement.offsetHeight);
}
Accessing nativeElement directly is discouraged but current Angular doesn't provide other ways as far as I know.
update
https://github.com/angular/angular/pull/8452#issuecomment-220460761
mhevery commented 12 days ago
We have decided to remove Ruler service, and so it is not part of the public API.
original
As far as I know the Ruler class should provide that functionality
https://github.com/angular/angular/blob/master/modules/angular2/src/platform/browser/ruler.ts if this isn't enought you probably need to access elementRef.nativeElement and use direct DOM access and functions provided by the elements.
new Ruler(DOM).measure(this.elRef).then((rect: any) => {
});
Rules service is safe in WebWorker.
See also the comments on https://github.com/angular/angular/issues/6515#issuecomment-173353649
<div #getElementHeight>
Height
</div>
Height of element is {{ getElementHeight.offsetHeight }}
<div *ngFor="let item of items" (click)="itemClick($event.currentTarget)"></div>
itemClick(dom){
var height=dom.clientHeight;
// ...
}

How to set a parent property from within a custom element in Aurelia?

A few days ago I asked this question 2 way databinding in Aurelia custom elements - bind custom element to parent viewmodel
Now I need to be able to reuse the allSelectableValues from my custom element (my-custom.js) in my parent element (create.js).
I need this for a custom value converter I have on create.js which contains some Ids which I need to display names for instead, by looping through the array of elements, currently fetched and residing in my custom element.
**create.html**
<td>${d.SomeID | allSelectableValuesMapping}</td>
and
**value-converters/all-selectable-values-mapping.js**
export class AllSelectableValuesMappingValueConverter {
toView(value) {
for(let item in allSelectableValues) {
if (item.SomeID == value){
return item.Name;
}
}
}
}
In the ideal world I'd have hoped something like this would have worked:
**my-custom.js**
async attached() {
this.allSelectableValues= await await this.myService.getAllValues();
this.parent.allSelectableValues = this.allSelectableValues;
}
But my custom element have no idea of the parent which is requiring it.
Does anyone have an idea how to set the parent's allSelectableValues equal to the custom element's allSelectableValues from within the custom element? Or is there another, better way of achieving it, while still maintaining the two-way databound custom element?
Something like this ?
Please take extra note of the #customElement('CustomElement') declarator above the export class CustomElement line of code.
Custom Element View Model
import {inject} from 'aurelia-framework';
import {customElement} from 'aurelia-framework';
import {bindable} from 'aurelia-framework';
#customElement('CustomElement')
export class CustomElement {
#bindable arrItems
}
Custom Element HTML
<template>
<div repeat.for="item of arrItems">$(item.someProperty}</div>
</template>
Parent View Model
export class ParentViewModel {
parentArrItems = [];
}
Parent HTML
<template>
<require from="customelement"></require>
<CustomElement arrItems.bind="parentArrItems"></CustomElement>
</template>