ssuperczynski
ssuperczynski

Reputation: 3416

Angular2 inject parent service into child

Given I have simple app component:

import {Component} from 'angular2/core';
import {bootstrap}    from 'angular2/platform/browser';
import {AppComponent}    from 'ng2-easy-table/app/app.component';
import {ConfigService} from "./config-service";

@Component({
  selector: 'app',
  directives: [AppComponent],
  providers: [ConfigService],
  template: `
    <ng2-table [configuration]="configuration"></ng2-table>
  `
})
export class App {
  constructor(private configuration:ConfigService) {}

}
bootstrap(App, []);

and ng2-table, which is being installed via npm install, and is placed in node_modules directory.

import {Component, OnInit, Input} from 'angular2/core';

@Component({
  selector: 'ng2-table',
})

export class AppComponent implements OnInit{
  @Input configuration;
  constructor() {
    console.log("configuration: ", this.configuration); // <-- null
  }

  ngOnInit() {
    console.log("configuration: ", this.configuration); // <-- null
  }
}

and this config service:

import {Injectable} from "angular2/core";
@Injectable()
export class ConfigService {
    public searchEnabled = true;
    public orderEnabled = true;
    public globalSearchEnabled = true;
    public footerEnabled = false;
    public paginationEnabled = false;
    public exportEnabled = true;
    public resourceUrl = "http://beta.json-generator.com/api/json/get/E164yBM0l";
}

In the app component I put ng2-table component. ng2-table and app are root components, so I am not allowed to use @Input() (this is the reason why [configuration]="configuration" does not work (following this answer https://stackoverflow.com/a/33155688/1168786).
The question is - how do I inject some service from app component into ng2-table component, but not using @Input().

How do I pass some config to my ng2-table, or even easier, how can I initialise component from node_modules which expects some config in constructor?

This is component link: https://github.com/ssuperczynski/ng2-easy-table/tree/master/app

Upvotes: 6

Views: 8427

Answers (5)

Gray Young
Gray Young

Reputation: 39

Use FactoryProvider to provide the service from its parent.

export const LOCATION_SERVICE_PROVIDER: FactoryProvider = {
  provide: LocationService,
  deps: [
    [new Optional(), new SkipSelf(), LocationService],
  ],
  useFactory: function (
    parent: LocationService
  ) {
    return parent || new LocationService();
  }
};

Upvotes: 0

user2992476
user2992476

Reputation: 1646

Why don't you simply inject by constructor the service that you are providing in the parent component?

You don't need to define extra inputs to pass the configuration. That's not a good practice.

@Component({
  selector: 'app',
  directives: [AppComponent],
  providers: [ConfigService],
  template: `
    <ng2-table></ng2-table>
  `
})
export class App {
  constructor(private configuration:ConfigService) {}

}

Then you can just inject the parent provider:

  @Component({
  selector: 'ng2-table',
})

export class AppComponent implements OnInit{
  
  constructor(private configuration:ConfigService) {
    console.log("configuration: ", this.configuration); // <-- null
  }

  ngOnInit() {
    console.log("configuration: ", this.configuration); // <-- null
  }
}

Upvotes: 0

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657396

@Input in @Input configuration; is missing () it should be

@Input() configuration;

I copied your code to the Plunker and adding () fixed it.

Plunker example

Upvotes: 5

James Salas
James Salas

Reputation: 176

Angular's dependency injection will provide the same instance of ConfigService to the child component as the parent component as long as it's not explicitly specified in the child component's providers property. This is due to Angular's hierarchal DI model, you can find more information in their docs. Based on the code samples, it looks like ConfigService might not using DI so you might want to look at turning it into an Injectable as well: DI info

Upvotes: 8

Thierry Templier
Thierry Templier

Reputation: 202196

This line doesn't seem to be correct since I guess that you want to evaluate the configuration expression:

<ng2-table [configuration]="'configuration'"></ng2-table>

I would use the following instead

<ng2-table [configuration]="configuration"></ng2-table>

Moreover I would inject your service (if it's actually a service) this way:

(...)
import {ConfigService} from "./config-service";

export class App {
  constructor(private configuration: ConfigService) {
  }
}

Upvotes: 1

Related Questions