Pass data - object from child to parent Angular 6 - parameter-passing

In child component, I have a datatable, when I click on the row, I will get data and keep it in branchToDivision, I also have a button, when I hit that button, I can send branchToDivision to the parent component.
Child component
#Output() messageEvent: EventEmitter<BranchDto> = new EventEmitter<BranchDto>();
branchToDivision: BranchDto;
onSelect(record: BranchDto) {
this.branchToDivision = new BranchDto();
this.branchToDivision = record;
console.log(this.branchToDivision);
console.log(this.branchToDivision.brancH_CODE);
}
acceptBranch() {
this.onSelect(this.branchToDivision);
this.messageEvent.emit(this.branchToDivision);
this.branchModalDivision.hide();
}
Parent Component
branch: BranchDto;
getBranch(branch: BranchDto): void{
this.branch = branch;
console.log(this.branch);
console.log(this.branch.brancH_CODE);
}
Parent HTML
<branchModal #branchModal (messageEvent)="getBranch($event)" ></branchModal>
I try to log branch property but it is undefined, What's wrong? Any idea is helping me well.

This is a way to send information from child component to parent component:
parent.component.html:
<div>
<child (getData)="getData($event)"></child>
</div>
in parent.component.ts:
public getData(value): void {
console.log(value) // welcome to stackoverflow!
}
in child.component.ts:
import {Output, EventEmitter} from '#angular/core';
#Output() public getUserData = new EventEmitter<string>();
this.getUserData.emit('welcome to stackoverflow!');
I hope my help is effective ツ

Related

how to refresh UI without reloading the page in Angular

I have a multiple charts in my page and I'm trying to make a delete call but some reason my chart UI is not updating immediately when I click the delete button. I always need to refresh the browser in order to see the changes.
I uploaded the full code for this two component her https://stackblitz.com/edit/angular-ivy-nnun96 so I would be really appreciated if I can get any suggestion on how to make the UI remove the Chart immediately when the user press Delete button.
Mc Chart List TS
deleteChart(){
this.chartService.deleteChart(this.chart.guid).subscribe((deleted) => {
console.log(deleted);
});
}
Mc Chart List HTML
<button mat-menu-item (click) = "deleteChart()" *ngIf = "chart.hasAccess && chart.canEdit && !chart.isPublished">Delete Chart</button>
Parent HTML
<mc-chart-list [chart]="chart" [editMode]="true" [wsType]="workspace.type"></mc-chart-list>
Parent TS
ngOnInit(): void {
this.charts = this.workspace.charts;
}
It look like this right now
You can use ChangeDetectorRef to detect changes on the view.
import {ChangeDetectorRef} from '#angular/core';
constructor(private ref: ChangeDetectorRef)
deleteChart(){
this.chartService.deleteChart(this.chart.guid).subscribe((deleted) => {
console.log(deleted);
this.ref.detectChanges();
});
}
Note: Remove changeDetection: ChangeDetectionStrategy.OnPush (if you are using it)

How to prevent flickering when using *ngIf?

In my app.component.html:
<html>
<head></head>
<body>
<header *ngIf="loggedIn && showHeader"></header>
<router-outlet></router-outlet>
</body>
</html>
In my app.component.ts:
export class AppComponent {
constructor(private HeaderService: HeaderService, private AuthService: AuthService) { }
get loggedIn(): boolean { return this.AuthService.getUserState(); }
get showHeader(): boolean { return this.HeaderService.getToggleState(); }
}
In my header.service.ts:
We created this service because there are other specific components after login where the header also needs to be hidden.
#Injectable({
providedIn: 'root'
})
export class HeaderService {
showHeader = true;
constructor() { }
setToggleState(state: boolean) {
this.showHeader = state;
}
getToggleState() { return this.showHeader; }
}
Now, in my login.component, the header should be invisible.
What's happening right now, is that there's a brief moment of flicker (seems to happen when you login and then logout, and return to login page) where the header is visible before it's hidden (and yes, also throws up ExpressionChangedAfterItHasBeenCheckedError).
What's the best way to achieve this? Should I just set showHeader to false by default?
login.component.ts
export class LoginComponent implements OnInit {
ngOnInit() {
// To hide the header
this.HeaderService.setToggleState(false);
}
}
When you use *ngIf, the element is not in the DOM (if the condition is false) and will be placed into the DOM in runtime.
Instead, you could use [hidden]="<your condition>", because then your element will be present in the DOM even though the condition is false. If then your condition changes to true, the elements' opacity will be changed from 0 to 1, which makes the element visible.
Now, in order to get a smoother transition, you can put some CSS on your DOM element like this:
.your-element {
transition: visibility 0.5s;
}
By that you get a hover-like effect.
Also, for your second problem (short flickering of the header before the data is there): This can be explained because you initialize showHeader with true. So it shows up at first, then it suddenly disappears when the service is initialized.
So in that case just set it to false at initialization.
Hope that helps :)
You can simply add
ngOnDestroy(){
this.service.setToggleState(true);
}
in login component.
You can set default value to true in service. then when you need to not display the header in which components then set ngoninit to false and ngondestroy to true to avoid flickering.
see here for example https://stackblitz.com/edit/angular-krit8a

How to render component by adding the component using innerHTML?

I have a component A which only contain a div with an id and a buttons that renders a component inside the div using innterHTML document.getElementById('my-router-outlet').innerHTML = '<app-component-b-page></app-component-b-page>';. But this is not rendering I wonder why?.
I'm trying to avoid using ngIf to be a selector for which component should be rendered for performance reason. Also if I clear the innerHTML does the resources of that component will be cleared?
Okay so a few things here
innerHTML = '<app-component-b-page></app-component-b-page>' is never going to work, angular wont recognise the angular component tag from a innerHTML call
using *ngIf wont affect the performance of the page, so doing the following
<app-component-b-page *ngIf="value === true"></app-component-b-page>
is probably you best option here
If you really don't want to use *ngIf you can use #ViewChild and ComponentFactoryResolver
In your HTML
<!-- this is where your component will be rendered -->
<div #entry></div>
In your component
import { Component, OnInit, ViewChild, ViewContainerRef, ComponentFactoryResolver } from '#angular/core'
import { YourComponent } from ... // import the component you want to inject
// ...
export class ...
#ViewChild('entry', {read: ViewContainerRef, static: true }) entry: ViewContainerRef;
constructor(
private _resolver: ComponentFactoryResolver
) {}
showComponent() {
const factory = this._resolver.resolveComponentFactory(YourComponent);
// this will insert your component onto the page
const component = this.entry.createComponent(factory);
}
// and if you want to dynamically remove the created component you can do this
removeComponent() {
this.entry.clear();
}
You are adding the element to the dom directly and it's not rendered by Angular.
You should go for the *ngIf.

angular using #output to sent data from child to parent component

I have some data that I am passing from my child to parent component and I want it to check if its empty or it has some value inside automatically.
this is in my login.compunent.ts - child ts
#Output() update=new EventEmitter<string>();
userEmail = "a#b.com";
authUser(loginForm) {
this.update.emit(userEmail);
this.router.navigate(['/home']);
}
this is in my app.compunent.ts - parent ts
emailData:string;
onUpdate(userEmail:string){
console.log("userEmail")
if(userEmail !== ''){
this.emailData = userEmail
console.log(userEmail)
}
}
this is in my app.compunent.html - parernt html
{{emailData}}
<router-outlet (update)="onUpdate($event)"></router-outlet>
I'm not sure I understand you completely but if you want to pass data from your child to your parent "automatically" I believe you have to implement a two-way bindable property.
You do that like this
child.ts
export class SomeComponent {
...
#Input() something;
// it's important to name it with the 'Change' suffix
#Output() somethingChange = new EventEmitter();
...
parent.html
<some-component [(something)] = "someFieldYouWantToTwoWayBindTo"></some-component>
now whenever you update something from your child the field someFieldYouWantToTwoWayBindTo will also be updated
Now if you want to check what's in something and only filter certain cases then implement a setter for someFieldYouWantToTwoWayBindTo
parent.ts
_someFieldYouWantToTwoWayBindTo
set someFieldYouWantToTwoWayBindTo(value) {
if(value !== '')
this._someFieldYouWantToTwoWayBindTo = value;
}

In angular2, how to call a function inside an element without mouse event?

Below is part of code in parent component, I already get the enable value from eventEmitter in its child component, which is enable=true.
<img src="{{currentImg}}" alt="Play Image not found" (click)="onMouseClick()">
<pause-button (isPauseBtnClicked)="enable = $event"></pause-button>
status is: {{enable}}
Then how can I assign a value for currentImg="someImg.png" after it listened the eventEmitter(enable=true)? Should I write a function? if so, how can I call that function in img tag without any mouse event?
I konw with mouse click event, things becomes easier, currentImg can be assign a value inside function.
onMouseClick() {
this.currentImg = this.clickedImg;
}
Look I don't know what you want to achieve. But writing this answer by thinking that you want to go with EventEmitter way without calling any mouseevent.
Note: Your expectation might be different. But It might help you out. If doesn't, kindly use it as a reference. I might have understood something completely different but purpose is not to guide you in wrong way
<img src="{{currentImg}}" alt="Play Image not found" (click)="onMouseClick()">
<pause-button (isPauseBtnClicked)="fire($event)"></pause-button><br>
status is: {{enable}}<br> // haven't played with status
{{currentImg}}
boot.ts
fire(arg) {
console.log('test start');
//this.animate.subscribe((value) => { this.name = value; });
this.currentImg=arg;
console.log(arg);
}
Working Plunker
PasueButton.ts
#Component({
selector: 'pause-button ',
template: `
________________________________________________________
<br>
I'm child
<br>
<img src="img path" (click)="clickMe()"/>
<= click the img
<br>
_____________________________________________________
`
,
})
export class PasueButton implements OnInit {
#Output() isPauseBtnClicked: EventEmitter = new EventEmitter();
constructor() {
console.log('Constructor called');
}
ngOnInit() {
console.log('onit strat');
}
clickMe()
{
this.isPauseBtnClicked.next('child Img path is copied');
}
}