Nguyen Tran
Nguyen Tran

Reputation: 1188

Access parent component from child component when parent component using ng-content Angular

I'm trying to access parent component from child component using dependence injection. It works, I can access to parent to using its methods and properties but I have not seen this approach on Angular doc. So do you have any idea about this approach? Should I use it?

Because the parent component using ng-content (like transclude angularjs) so I cannot using EventEmitter @Output approach.

The bellow is my code:

wizard.component.ts (parent)

import { Component, OnInit } from '@angular/core';

@Component({
    selector: 'wizard',
    template: `
        <div>
            <ng-content></ng-content>
            <button>Back</button>
            <button>Next</button>
        </div>
    `
})
export class WizardComponent implements OnInit {
    steps = [];

    constructor() { }

    addStep(step) {
        this.steps.push(step);
    }

    ngOnInit() { }
}

step.component.ts (child)

import { WizardComponent } from './wizard.component';
import { Component, OnInit } from '@angular/core';

@Component({
    selector: 'step',
    template: `
        <div>Step <ng-content></ng-content></div>
    `
})
export class StepComponent implements OnInit {
    constructor(private parent: WizardComponent) { 
        this.parent.addStep(this);
    }

    ngOnInit() { }
}

app.component.html (main app)

<wizard>
    <step>1</step>
    <step>2</step>
    <step>3</step>
</wizard>

Looking forward to hearing your opinions. Thanks!

Upvotes: 4

Views: 11507

Answers (5)

Ahmed Samir Elshazly
Ahmed Samir Elshazly

Reputation: 229

Another approach is to use a class interface and find the parent using this class interface

The class interface: It's an abstract class used as an interface rather than as a base class.

Based on the definition, the parent should implement the class interface.

A scenario: If we have a child class called 'AppleComponent' and we need to access it's parent class 'FruitsComponent' inside this child class to get the props/methods of this parent.

1- Make the class interface

export abstract class Parent {
    abstract amount: number;
}

Here we defined the class that will be implemented by the parent and it'll have an abstract property as an example that will be defined in the FruitsComponent.

2- Update the Fruits class

@Component({
...
providers: [{ provide: Parent, useExisting: forwardRef(() => FruitsComponent) }],
})

export class FruitsComponent implements Parent{ 
  public amount = 5;
   ....
}

3- Accessing the parent class inside the child class

export class AppleComponent {
  constructor( @Optional() public parent?: Parent) { 
    console.log('The amount in the parent is: 'this.parent?.amount) 
  }
  ...
}

The result from the console

The amount in the parent is: 5

That's it.

Refrence: Find a parent by its class interface

Upvotes: 0

Hannes
Hannes

Reputation: 91

The docs for parent DI / known parent moved here:

https://angular.io/guide/dependency-injection-navtree#find-a-parent-component-of-known-type

Upvotes: 1

Matthew Parton
Matthew Parton

Reputation: 79

You can provide parent and child communication by creating a property on the parent object that uses the querylist. You must also add a property or method on the child component to receive the parent pointer.

@ContentChildren( OptionComponent )
public Options: QueryList<OptionComponent>;

This will give you a pointer to all the children in the parent object. These can be projected entries (ngContent) or direct html declarations. The query list will then grab a pointer to each child for you.

then in your in you parent object

public ngAfterViewInit(): void
{
    this.Options.forEach( ( item ) =>
    {
        item.Parent = this;
    } ) 
}

Grossly simplified but I think this provides the basic idea.

Upvotes: 1

Nguyen Tran
Nguyen Tran

Reputation: 1188

Finally I found the document about parent dependence injection here https://angular.io/docs/ts/latest/cookbook/dependency-injection.html#!#known-parent.

And there is an article that using it: https://blog.thoughtram.io/angular/2015/04/09/developing-a-tabs-component-in-angular-2.html

Hope it will help someone who has the same concern like me.

Upvotes: 1

Aravind
Aravind

Reputation: 41533

Parent Component-> Wizard Component

@Component({
  selector: 'wizard',
  template: `
    <div>
      <steps [steps]="steps"> </steps>
      <button> Back </button>
      <button> Next </button>
      <button (click)="addStep()"> Add a step </button>
    </div>
  `,
})
export class WizardComponent {
  steps:any[]=new Array();
  constructor() {
    this.steps.push({id:1,name:'abc'});
    this.steps.push({id:2,name:'abc'});
    this.steps.push({id:3,name:'abc'});
  }
  addStep(){
    let count = parseInt(this.steps.count) + 1;
    this.steps.push({id:count,name:'abc'});

  }
}

StepComponent -> Child component

@Component({
  selector: 'steps',
  template: `
    <div>
      <span *ngFor="let step of steps">
            <label> {{step.id}} </label>
             <div> {{step.name}} </div>
      </span>
    </div>
  `,
})
export class StepsComponent {
  @Input() steps:any[]=new Array();
  constructor() {

  }

}

Update 1: Different elements will be present in each steps, so I suggest you to use the <ng-content> as below

<div>
     <ng-content select=".step-body"> </ng-content>

</div>

Your wizard will look like

  <table>
    <tr>
        <td>
            <steps>
                <div class="step-body">
                hi hello

                </div>
              </steps>
        </td>
        <td>
            <steps>
                <div class="step-body">
                something else

                </div>
            </steps>
        </td>
    </tr>
    </table>

LIVE DEMO

Upvotes: 1

Related Questions