Trigger child to update - html

Hi I'm new to Angular and any help would be great. The parent of my component has a method to generate different rules for each picker, but the rules also change dynamically from the parent so I need to make my picker component call the disableoption method and updating its own Options when the parent has been updated.
<picker-component *ngFor="let parameter of product.parameters" [parameter]="parameter" [disabledOptions]="disabledOptions(parameter)"></picker-component>

It's possible to inject the parent in the child (I'm not telling this is the best approach to your case, I'm just answering your question):
<parent> <!-- ParentComponent typescript class -->
<child></child> <!-- ChildComponent typescript class -->
</parent>
export class ChildComponent {
constructor(private _parentComponent: ParentComponent) {
this._parentComponent.disabledOptions(parameter);
}
}
In cases like this, a service injected in both ParentComponent and ChildComponent usually is a better and easy-to-implement approach though.

Related

How to reuse the component

Factor is a component and Idea is an another component I need to show all the data's of Factor in the Component Idea.Can anyone say How to reuse the component.
You need to use #Input() for passing data into child component, and #Output() for emitting event from child component. You can refer to the documentation for more clarity https://angular.io/guide/inputs-outputs
you creat a component like :
ng g component xyz
after using selector reuse component Like
=> <app-xyz(component-Name)></app-xyz(component-Name))

How to add or remove CSS class of an external library component from our own component in Angular

I have a component which has an external library component. I want to change toggle one class of external library component based on some condition in my own component. Here thus, I can not use ngClass. I could use document.querySelector but I dont want to use it. Is there any other way?
You can use ViewChild in your component class to reference the external library component, configuring ViewChild's read option to give you the component as an ElementRef so you can then toggle the DOM element class.
For example, if the external component in your component's template looks like this:
<div>
<external-component class="toggle-me"></external-component>
</div>
You can attach a template reference variable to it, like so:
<div>
<external-component #exComp class="toggle-me"></external-component>
<!-- ^^ add this template reference variable -->
</div>
Then in your component class, use ViewChild to get a hold of the external component using that template reference variable, specifying { read: ElementRef } so you get its DOM element rather than its component class instance:
#ViewChild('exComp', { read: ElementRef }) externalComponent: ElementRef;
With that, you can then access the nativeElement and its classList to toggle the class:
this.externalComponent.nativeElement.classList.toggle('toggle-me');
Alternatively, if you didn't want to add a template reference variable, or were not able to, you could pass the external component's class name, rather than the template reference variable name, to ViewChild.
#ViewChild(ExternalComponent, { read: ElementRef }) externalComponent: ElementRef;
Here's a StackBlitz showing both options.

Changing fxFlex value in the Component with "setAttribute('fxFlex', '25%')" not Working in Angular 6

I'm using flexLayout module (see more in https://github.com/angular/flex-layout also in https://alligator.io/angular/flex-layout/) to build responsive div in my Angular application and I want to set the value of fxFlex attribute from my Angular Component.
code in the component.ts:
const nav = document.getElementById('nav2'); nav.setAttribute('fxFlex', '5%');
code in the html page:
<div fxLayout>
<div id="nav2" fxFlex="25%" class="col-md-2.5 bg-white p-1">hello</div>
<div id="nav1">word</div></div>
the code should normally should change the size Layout to 5%, but it's not the case, when i inspect the page I found that the attribute has been change but the layout still the same, oddly when i change it manually in the html code to 5%, i get the result that i wanted.
I'm using Angular 6, and Typescript 3.1.1
Please, If there is any suggestion, do not hesitate.
Thank You !
the code should normally should change the size Layout to 5%
No it should not.
Angular directives are ussed in Typescript, or in a pre-build context.
When you write
document.getElementById('nav2'); nav.setAttribute('fxFlex', '5%')
You instruct the Javascript, that has been compiled from Typescript (so in a post-build context) to get the element and add an Angular directive to your attribute.
The thing is, the code is already compiled, so you can't add typescript to Javascript, otherwise you would have to compile it again (and I'm not even sure you can do that).
I suggest you learn about angular features and how it works before using it. Also, consider posting a Minimal, Complete, and Verifiable example if you want someone to offer a solution adapted to your case.
In angular, you need to use the renderer2 to setAttribute dynamically.
Example:
HTML
<div #myDiv id="nav2" fxFlex="25%" class="col-md-2.5 bg-white p-1"></div>
component.ts
import {ElementRef,Renderer2} from '#angular/core';
...
export class MyComponent implements AfterViewInit {
#ViewChild('myDiv') el:ElementRef; // get the refernce of dom element.
constructor(private rd: Renderer2) {}
ngAfterViewInit() {
// Update dom after view initialized.
this.renderer2.setAttribute(this.el.nativeElement, "fxFlex", "5%");
}
}

Create a master table component and add child columns dynamically in angular

Good morning everyone !
So have to create an application that displays many tables that all look the same (except their columns of course and the objects inside).
I have a master table component which can be summarized by:
<master-table>
<!-- here I define the master table style, pagination, etc etc
which is the same everywhere -->
</master-table>
In the master table component TS file I have basically options that are relevant for every page where this kind of table should be displayed, such as filterDate, clearSelection etc etc etc nothing very special.
The point is, I don't want to repeat this code every where because it is not necessary, so my idea was to create several component that would extend the master table component.
It works fine for the typescript values, but I am stuck with the HTML.
In my master table HTML I would like at some point some kind of placeholder something like this:
<master-table>
<standard-for-all-table></standard-for-all-table>
<!-- insert here child columns -->
</master-table>
In the components that extends my master table I was imagining then something like:
<!-- child component -->
<master-table></master-table>
<child-column>column definition</child-column>
Doing this would allow me to define only the columns in the child components HTML and they would be added automatically to the parent HTML at runtime...
Any idea how to do this ?
Cheers and thanks !
Basically you have to create your main master-table component and your generic list chid-column component and insert it in your parent html template structure.
I've edit the final part hope in a better understanding way...
Then you can structure your child component to contain all the properties you need and thanks to *ngIf show only the properties you return from your provider methods i.e. getClients(), getUsers(), getHouses(), also thanks to the #Input decorator you can inject this data directly from the parent to the child and create many components you want with just a change of the data.
So in your parent you can have something like
import { Component } from '#angular/core';
import { MY_DATA_FROMP_ROVIDER } from './mydata/provider';
#Component({
selector: 'master-table',
template: `
<ul>
<child-column *ngFor="let item of items"
[item]="item">
</app-hero-child>
</ul>
`
})
export class MasterTableComponent {
items:any
constructor(public data: MYDATAFROMPROVIDER) {
this.items = MYDATAFROMPROVIDER.myGetMethod();
}
And in your child
import { Component, Input } from '#angular/core';
import { INTERFACE } from './mydata/interface';
#Component({
selector: 'child-column',
template: `
<div *ngIf="item.id">{{item.id}}</div>
<div *ngIf="item.name">{{item.name}}</div>
<div *ngIf="item.address">{{item.address}}</div>
<div *ngIf="item.phone">{{item.phone}}</div>
`
})
export class ChildColumnComponent {
#Input() item: INTERFACE;
}
If you want to go deeper: Component Interaction
This guide is from official angular page Here
Here is the live sample of it
Not sure if these links could help.
But I actually worked on a project where we want to dynamically loading Child component into a Grid(Parent component).
And later on we can pass any component with different view inside the Grid
Guess that pretty close to your goal.

Get details of object from unrelated element in angular

I am following the basic 'Tour of Heros' tutorial and sort of adding my own needed elements as I go (bootstrap, ng-bootstrap etc) and I want to grab the 'selected hero' from hero details when I reach it and put the name of the hero in a navbar component.
Like so, but obviously with a way to access the selected hero
<div *ngIf="selectedHero">
<li class="nav-item">
<div class="nav-link" routerLink="/detail" routerLinkActive="active">{{selectedHero.name}}</div>
</li>
</div>
My navbar is called by app.component.html above the routing outlet
<app-navbar></app-navbar>
<div class="container">
<router-outlet></router-outlet>
</div>
I have already looked up several questions related to this sort of thing but havnt really found anything made sense or worked when I tried it (I am assuming I am not doing them correctly or a similar issue)
I am new to angular and I feel like this sort of access is something I should know asap
I have seen 'emitters' and 'parent-child relationship' etc but not sure how to go about that with my navbar and the selected hero. The tutorial im following (that has all the code that im working with) is: https://angular.io/tutorial
Edit Ive also considered just calling the 'navbar' component within every other main component (as in, within 'hero-detail.component.html' above the actual information) but I think that goes against standards/repeating code?
The hero details component and the navbar component have no relationship, so to share data between them you simply need to create a shared service between them that can pass data back and forth like this:
selected-hero.service.ts
import {Injectable} from '#angular/core';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
#Injectable()
export class SelectedHeroService {
selectedHero = new BehaviorSubject<string>('Default Name Of Hero To Be Shown Goes Here');
selectedHeroObservable = this.selectedHero.asObservable();
changeSelectedHero(newHero:string):void{
this.selectedHero.next(newHero)
}
}
and then in your navbar component, you can read the selected hero like this:
navbar.component.ts
constructor(private sh: SelectedHeroService ) {
this.sh.selectedHeroObservable
.subscribe((hero) => {
//add your logic here!! for now I'm just gonna console log the selected hero
console.log(hero);
});
}
To set a new hero in you heroes details component you call this method:
hero-details.component.ts
changeSelectedHero(){
this.sh.changeSelectedHero('My New Selected Hero');
}
and don't forget to add the service in the provides arrays and both of the components in the declarations array of the same module so you don't get any errors. Also, don't forget to unsubscribe from the selectedHeroObservable to avoid memory leaks.
Component interaction in Angular could be simplified as i use angular at least to three ways: #ViewChild, EventEmitter (Output) or Input.
Viewchild is as it sound when you have a child component and you could set variable declaration (#) in the template to directly have access to methods on the child component.
Eventemitter is used in the child component when you want to notify the parent.
Input is used to set a property in a child.
A part from these three ways to communicate within components there is also services. I use this aproach when the components are too far from each other.
And to answer your question i would go with the service aproach. Have a look at subjects. Check out this plunker!!
export class MessageService {
private subject = new Subject<any>();
sendMessage(message: string) {
this.subject.next({ text: message });
}
clearMessage() {
this.subject.next();
}
getMessage(): Observable<any> {
return this.subject.asObservable();
}
}
http://plnkr.co/edit/FHIPt1?p=preview