6

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

Community
  • 1
  • 1
ssuperczynski
  • 3,190
  • 3
  • 44
  • 61
  • I am having trouble figuring out how the service instance from the parent is shared with the child component in this example: https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service –  Dec 10 '18 at 07:49
  • Ah I think @James Salas answer answers my question –  Dec 10 '18 at 07:50

5 Answers5

8

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

James Salas
  • 176
  • 1
  • 5
  • Really nice article, will read it. After you answer I attached my `configService` to the question, I think is fine (hope so) – ssuperczynski Apr 09 '16 at 15:59
  • 1
    This is the correct answer, not the accepted one. Services should not be injected using input property. +1 – Narendra Pathai Apr 06 '17 at 07:28
  • @NarendraPathai yes I think you are right. I suppose you could inject the service via input property, but it would be redundant. –  Dec 10 '18 at 07:50
5

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

@Input() configuration;

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

Plunker example

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • I am having trouble figuring out how the service instance from the parent is shared with the child component in this example: https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service –  Dec 10 '18 at 07:49
  • I think @James Salas' answer is better than this one, and answers my question above as well. –  Dec 10 '18 at 07:51
  • But it doesn't answer the original question. Go with James' answer of course if it answers **your** question better. – Günter Zöchbauer Dec 10 '18 at 07:54
  • no I think it is redundant to inject the service into the child, the instance is already shared –  Dec 10 '18 at 07:55
1

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) {
  }
}
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • Thanky you Thierry for the answer, I tried your solution, bot still config is not being pass to child component. I edited a little bit question, because `console.log` is not showing `undefined` only `null` – ssuperczynski Apr 09 '16 at 15:54
  • You're welcome! Is your configuration object not null in the App component? – Thierry Templier Apr 10 '16 at 13:19
  • I would like to pass actually anything, even I am passing some string `` I am getting `null` – ssuperczynski Apr 11 '16 at 15:49
0

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
  }
}
user2992476
  • 1,536
  • 2
  • 17
  • 29
0

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();
  }
};
Gray Young
  • 41
  • 4
  • This could use more context. – OneHoopyFrood Mar 15 '22 at 18:25
  • 1
    See "[Explaining entirely code-based answers](https://meta.stackoverflow.com/q/392712/128421)". While this might be technically correct, it doesn't explain why it solves the problem or should be the selected answer. We should educate along with helping solve the problem. – the Tin Man Mar 22 '22 at 04:19