angular 2 child reference to variable into parent - javascript

How to change the value of a variable or use a method in a parent component from a child component without using input and output
I try something like this but not working.
#Component({
selector: 'child',
template: `
<div>
<h2>{{name}}</h2>
<button (click) = "rename()" > Rename Parent </button>
</div>
`,
})
export class Child {
name:string;
constructor() {
this.name = 'child'
}
rename() {
App.name = 'Rename';
}
}
#Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
</div>
<child> </child>
`,
})
export class App {
name:string;
constructor() {
this.name = 'Angular2'
}
}
example here
plunker example

Input and Output are just made for this. It is, according to the Angular2 Documentation, made for communication between parent and child components.
#Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
</div>
<child [name]="this.name" (nameChanged)="this.name = $event"> </child>
`,
})
export class App {
name:string;
constructor() {
this.name = 'Angular2'
}
}
#Component({
selector: 'child',
template: `
<div>
<h2>{{name}}</h2>
<button (click) = "rename()" > Rename Parent </button>
</div>
`,
})
export class Child {
#Input() name:string;
#Output() nameChanged: EventEmitter<string> = new EventEmitter<string>();
constructor() {
}
rename() {
this.nameChanged.emit('Renamed');
}
}
Alternatively you could inject a service into both parent and child component, which has some values that both parent and child can access and modify. But make sure to add that service to either only the parent component or only the AppModule, otherwise you would get 2 instances of your service.

That is #Output and #Input in Angular 2.
Docs: https://angular.io/docs/ts/latest/cookbook/component-communication.html
Another way that is Observable, Subject you can also inject data from a child component to root component or from a component to another component : See this video: https://www.youtube.com/watch?v=U2qJxfi7370&list=PLFaW_8zE4amNEdKZOJD3P_GeV3Hgva7RD&index=10

Related

How to pass data from child to parent?

I need to pass one variable, that is inside my child component, to parent page.
This variable that I am trying to pass, is the array result of Barcode Scanner.
And I need to pass it to parent to send to API.
childComponent.ts
this.consultList;
parentComponent.ts
export class ParentComponent implements OnInit {
#Input() consultList: any[] = [];
testCall() {
console.log('Test Consult: ', this.consultList;
}
Here is an example stackblitz project to test parent-child data transfer, using #Input() and #Output()mechanism
import { Component, EventEmitter, Input, Output } from '#angular/core';
#Component({
selector: 'child',
template: `
<h1>Hello {{ name }}! This is child component</h1>
<button (click)="sendEventToParent()">Send data to parent</button>
`,
styles: [
`
h1 {
font-family: Lato;
}
`
]
})
export class ChildComponent {
#Input() name: string;
#Output() eventFromChild: EventEmitter<string> = new EventEmitter();
sendEventToParent(): void {
this.eventFromChild.emit('data from child');
}
}
here is the parent component html called child
<child name="{{ name }}" (eventFromChild)="onEvent($event)"></child>
<h1>This is parent component</h1>
<p>{{dataFromChild}}</p>
and event bindin like that
import { Component, VERSION } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
name = 'Angular ' + VERSION.major;
dataFromChild = '';
onEvent(event): void {
this.dataFromChild = event;
}
}
What you are thinking of is called an abstract class. An abstract class can define abstract properties just like an interface, abstract methods just like an interface, and unlike an interface it can actually implement methods. You cannot initialize an abstract class, but you can inherit code for re-use from it.
https://codesandbox.io/s/patient-breeze-h4s3t?file=/src/index.ts
abstract class Parent {
abstract someProperty: string;
someCall() {
console.log(this.someProperty);
}
}
class ChildOne extends Parent {
someProperty = "I am child one";
}
class ChildTwo extends Parent {
someProperty = "I am child two";
}
const one = new ChildOne();
const two = new ChildTwo();
one.someCall(); // "I am child one";
two.someCall(); // "I am child two";

Angular communication between two components

I'm building a simple web based application using angular version 6.
In my application there is a component which has a child component. There is a function in this component(In the parent component, not the child component.) and I want to invoke that function using a button which is in the child component.
This image explains the format of my components.
I think its regarding to angular #Output. But i can't manage it.
This is how my code has organized.
Parent Component - component.ts file
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-teacher-home',
templateUrl: './teacher-home.component.html',
styleUrls: ['./teacher-home.component.scss']
})
export class TeacherHomeComponent implements OnInit {
constructor() { }
ngOnInit() {
}
formView: boolean = false;
toggleForm(){
this.formView = !this.formView;
}
}
Parent component - component.html file
<div>
<child-compnent></child-compnent>
</div>
Child component - component.html file
<div>
<button>Toggle Form view</button>
</div>
i want to callthe function toggleForm() of parent component when the button clicked which is in child component.
read this article: Understanding #Output and EventEmitter in Angular
child component:
#Component({
selector: 'app-child',
template: `<button (click)="sendToParent('hi')" >sendToParent</button> `
})
export class AppChildComponent {
#Output() childToParent = new EventEmitter;
sendToParent(name){
this.childToParent.emit(name);
}
}
parent component:
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
toggle(){
console.log('toggle')
}
}
parent html:
<app-child (childToParent)="toggle($event)"></app-child>
working DEMO
You have a couple of ways to do this :
Is to create an event inside the child component and then give it a callback, something like this:
#Output('eventName') buttonPressed = new EventEmitter();
and call buttonPressed.emit() when you want the event to be triggered
on the parent side it will look like this :
<div>
<child-compnent (eventName)="toggleForm()"></child-compnent>
</div>
Another way is to create a shared service that will contain the shared functions and data for both components
You need to use #Output decorator inside your child component and emit an event when the button present clicked inside your child.
For eg: -
Child component.html
<div>
<button (click)="childButtonClicked()">Toggle Form view</button>
</div>
Child component.ts
export class ChildComponent {
#Output triggerToggle: EventEmitter<any> = new EventEmitter<any>();
...
childButtonClicked() {
this.triggerToggle.emit(true);
}
...
}
Parent Component
<div>
<child-compnent (triggerToggle)="toggleForm()"></child-compnent>
</div>
You can use EventEmitter of angular to listen to events from your child component.
parent.component.ts
toggleForm($event) {}
parent.component.html
<div>
<child-compnent (trigger)="toggleForm($event)" ></child-compnent>
</div>
child.component.ts
#Output() trigger : EventEmitter<any> = new EventEmitter<any>();
buttonClick(){
this.trigger.emit('click');
}

Nest two dynamically created components in Angular [duplicate]

I would like to set the body of <ng-content> while instantiating a component dynamically using ComponentFactoryResolver.
I see that I can get access to input & output using ComponentRef, but not a way to set <ng-content>.
Please note <ng-content> I'm planning on setting can contain simple text/can span dynamically created components
#Component({
selector: 'app-component-to-project',
template: `<ng-content></ng-content>`
})
export class ComponentToProject implements AfterContentInit {
ngAfterContentInit() {
// We will do something important with content here
}
}
#Directive({
selector: 'appProjectionMarker'
})
export class ProjectionMarkerDirective implements OnInit {
constructor(private viewContainerRef: ViewContainerRef, private componentFactoryResolver: ComponentFactoryResolver) {
}
ngOnInit() {
const componentFactory: ComponentFactory<ComponentToProject> = this.componentFactoryResolver.resolveComponentFactory(ComponentToProject);
const componentRef: ComponentRef<ComponentToProject> = this.viewContainerRef.createComponent(componentFactory);
// Question: How to set content before the child's afterContentInit is invoked
}
}
#Component({
selector: 'appTestComponent',
template: `<div appProjectionMarker></div>`
})
export class TestComponent {}
There is the projectableNodes parameter for the vcRef.createComponent method
createComponent<C>(componentFactory: ComponentFactory<C>, index?: number, injector?: Injector, projectableNodes?: any[][], ngModule?: NgModuleRef<any>): ComponentRef<C>;
You can use it to dynamically inject one component into another.
Let's say we have the following component
#Component({
selector: 'card',
template: `
<div class="card__top">
<h2>Creating a angular2 component with ng-content dynamically</h2>
</div>
<div class="card__body">
<ng-content></ng-content>
</div>
<div class="card__bottom">
<ng-content></ng-content>
</div>
`
})
export class CardComponent {}
We want to create it dynamically and insert some controls to its ng-content locations. It could be done like follows:
const bodyFactory = this.cfr.resolveComponentFactory(CardBodyComponent);
const footerFactory = this.cfr.resolveComponentFactory(CardFooterComponent);
let bodyRef = this.vcRef.createComponent(bodyFactory);
let footerRef = this.vcRef.createComponent(footerFactory);
const cardFactory = this.cfr.resolveComponentFactory(CardComponent);
const cardRef = this.vcRef.createComponent(
cardFactory,
0,
undefined,
[
[bodyRef.location.nativeElement],
[footerRef.location.nativeElement]
]
);
Plunker Example
See also
Why is projectableNodes an any[][]?
Pawel Kozlowski - Reactive parenting with Angular 2 - NG-BE 2016

Angular 2 - Get passed object to component via inputs

On my parent page I have a link here:
<a (click)="showPermissionsRates(5757);">Link</a>
The function sets it:
showPermissionsRates(item) {
this.currentEventPoolId = item;
}
With a child component on the parent page here:
<app-event-pools-permissions-rates [eventPoolId]="currentEventPoolId "></app-event-pools-permissions-rates>
And then in my child component TS file I use:
inputs: ['eventPoolId']
But how do I get that value of '5757' in the child component? Such as using alert?
You should be able to just use #Input() on the child property.
I've put this together showing a VERY basic example, but without more to go on regarding your issues, it's hard to know what you need:
https://plnkr.co/edit/y9clOla1WrPFmhMJoz7o?p=preview
The gist is to use #Input() to mark your inputs in the child component, and map those in the template of the parent.
import {Component} from '#angular/core'
import {BrowserModule} from '#angular/platform-browser'
import { ChildComponent } from 'child.component.ts';
#Component({
selector: 'my-app',
template: `
<div>
<button (click)="changeProperty('ABC 123')">Click Me!</button>
<child-component [childProperty]="parentProperty"></child-component>
</div>
`,
})
export class App {
public parentProperty: string = "parentProp";
public changeProperty(newProperty: string) : void {
this.parentProperty = newProperty;
}
}
Then, in the child:
import {Component, Input} from '#angular/core'
#Component({
selector: 'child-component',
template: `
<div>Hello World: {{ childProperty }}</div>
`,
})
export class ChildComponent {
#Input()
childProperty:string;
constructor() {
this.childProperty = 'childProp'
}
}
I think you are setting value to at input variable in a click event, then you have to listen for it in the child component constructor using ngonchanges
ngOnChanges(changes: SimpleChanges) {
if(changes['eventpoolid'] && changes['eventpoolid'].currentValue) {
// you get updated value here
}
}

Angular2 getting data from child route in app-root

In my app-root component I have router-outlet in container with some styles.
I have route:
{
path: 'some-path',
component: ChildContainer,
data: { variable:'variable' },
}
And I can to get variable in ChildContainer, but I need it in AppRoot. So, from documentation I can get it from child, but if I do this in AppRoot constructor:
const state: RouterState = router.routerState;
const root: ActivatedRoute = state.root;
const child = root.firstChild;
and console.log(root, child) - child is null, and root contains correct child (invoke property getter).
So, how can I get variable in AppRoot?
You may tap into activate event to get reference of instantiated component inside the router outlet.
Check This SO question
#Component({
selector: 'my-app',
template: `<h3 class="title">Basic Angular 2</h3>
<router-outlet (activate)="onActivate($event)" ></router-outlet>
`
})
export class AppComponent {
constructor(){}
onActivate(componentRef){
componentRef.sayhello();
}
}
#Component({
selector: 'my-app',
template: `<h3 class="title">Dashboard</h3>
`
})
export class DashboardComponent {
constructor(){}
sayhello(){
console.log('hello!!');
}
}
Here is the Plunker!!
Update
expose ActivatedRoute as a public property and once you have the routed component reference, subscribe to data,
onActivate(componentRef){
componentRef.route.data.subsribe(data => {
console.log(data);
});
}

Categories