1

I've done some reading about sharing a service between components and a the basic idea of using the app component which to my understanding is essentially creating a singleton of the service as a provider.

I load a component which has nested components and the nested components all use this shared service. An event in the future triggers on the page and I now need the HTTP service to update and update all the nested components template elements. How exactly do I "force" this update?

Also, does it mean that because I shared a service in the app component that the HTTP service will run whenever the page "root" component loads?

3
  • You don't need force anything. When Angular2 change detection detects a change, it will update the HTML. The HTTP request will be made when a component subscribes to it. If you do the subscribing from a services constructor, the request will be made when the service is injected somewhere the first time (this is when an instance is created). Commented Jul 29, 2016 at 16:27
  • Ye I kinda get the idea that when the service updates any subscribed components would update (directives correct?) but i'm trying to make sense of the fact that let's say I have a dashboard page & component with multiple nested components that need updating when the service updates, at what point do I actually call the service update? In the dashboard component after the nested components have loaded? Commented Jul 30, 2016 at 18:16
  • You would initialize the initial state using the ngOnInit interface on the component that receives the service, and execute the initialization logic within the ngOnInit lifecycle hook method. Any updates to the service afterward can be called at any point from any of the components. See angular.io/docs/ts/latest/guide/lifecycle-hooks.html Commented Jul 30, 2016 at 18:30

1 Answer 1

1

UPDATE: I didn't have time to put anything together this weekend, but in case things still aren't clear, I made a simplified example to show how service injection works in Angular 2.

The AppComponent lists the AppService as a provider in the @Component decorator, meaning that a singleton of the service is injected at this component level. In the ChildComponent, the service does not need to be listed as a provider because it will use the same instance injected into AppComponent. All it needs to do is import the AppService module, and inject the service in the constructor definiton.

Conversely, the IsolatedComponent uses a separate instance of AppService, so it DOES inject a new singleton instance via the providers array in its @Component decorator. The IsolatedChildComponent will use the same service instance used by the IsolatedComponent, so as with the ChildComponent, all it needs to do is import the AppService module, and inject the instance into its constructor definition.

Notice how each component updates the shared binding property, messages, whenever the component is initialized, and the child component automatically captures these updates. The same logic can be applied to services that make API calls.

Here is the code for the service and components:

app.service.ts

import { Injectable } from '@angular/core';

@Injectable()
export class AppService {
  messages: string[] = [];

  updateMessages(msg: string) {
    this.messages.push(msg);
  }
}

app.component.ts

import { Component, OnInit } from '@angular/core';
import { AppService } from './app.service';
import { ChildComponent } from './child.component';
import { IsolatedComponent } from './isolated.component';

@Component({
  selector: 'my-app',
  template: `
  <h1>AppComponent Tree</h1>
  <p>
    AppComponent and ChildComponent consume the same instance of AppService
  </p>
  <child-component></child-component>
  <hr />
  <isolated-component></isolated-component>
  `,
  providers: [AppService],
  directives: [ChildComponent, IsolatedComponent]
})
export class AppComponent implements OnInit {
  messages: string[];

  constructor(private appService: AppService) {
    this.messages = appService.messages;
  }

  ngOnInit() {
    this.addMessage(`AppComponent Initialized`);
  }

  private addMessage(msg: string) {
    this.appService.updateMessages(msg);
  }
}

child.component.ts

import { Component, OnInit } from '@angular/core';
import { AppService } from './app.service';

@Component({
  selector: 'child-component',
  template: `
  <div *ngFor="let message of messages">{{message}}</div>
  `
})
export class ChildComponent implements OnInit {
  messages: string[];

  constructor(private appService: AppService) {
    this.messages = appService.messages;
  }

  ngOnInit() {
    this.addMessage(`ChildComponent Initialized`);
  }

  private addMessage(msg: string) {
    this.appService.updateMessages(msg);
  }
}

isolated.component.ts

import { Component, OnInit } from '@angular/core';
import { AppService } from './app.service';
import { IsolatedChildComponent } from './isolated-child.component';

@Component({
  selector: 'isolated-component',
  template: `
  <h1>Isolated Component Tree</h1>
  <p>
    IsolatedComponent and IsolatedChildComponent consume an 
    instance of AppService separate from the AppComponent tree
  </p>
  <isolated-child></isolated-child>
  `,
  providers: [AppService],
  directives: [IsolatedChildComponent]
})
export class IsolatedComponent implements OnInit {
  messages: string[];

  constructor(private appService: AppService) {
    this.messages = appService.messages;
  }

  ngOnInit() {
    this.addMessage(`IsolatedComponent initialized`);
  }

  private addMessage(msg: string) {
    this.appService.updateMessages(msg);
  }
}

isolated-child.component.ts

import { Component, OnInit } from '@angular/core';
import { AppService } from './app.service';

@Component({
  selector: 'isolated-child',
  template: `
  <div *ngFor="let message of messages">{{message}}</div>
  `
})
export class IsolatedChildComponent implements OnInit {
  messages: string[];

  constructor(private appService: AppService) {
    this.messages = appService.messages;
  }

  ngOnInit() {
    this.addMessage(`IsolatedChildComponent initialized`);
  }

  private addMessage(msg: string) {
    this.appService.updateMessages(msg);
  }
}

See the Hierarchical Injectors documentation.

Sign up to request clarification or add additional context in comments.

5 Comments

So if you had a page that had multiple components that depended on the same service would you load in all the components and at the "bottom" of the page component call the service so that each component would then update? Maybe my question isn't completely clear?
I get what you're getting at. What you would do is inject the service as a provider in the first relevant parent component, then in any subsequent child component, inject the service in the constructor. All components in the tree would reference the same instance of the service, and any bindings affected by changes to the service would be reflected in the components automatically.
Now, if the components aren't in the same component tree, and you want them all to be orchestrated with the same service, you can still do so by injecting into the AppComponent, which should be a parent to any component in your Angular app.
So if I inject into AppComponent during what "event" does the service know to update? Or does the service update on every "page" load? This is for an internet banking app so maybe that will give you some idea of what im trying to achieve? Multiple "modules" on a page need to update with account balances after a transaction takes place + when the page initially loads, BUT only if the subscribed "modules" actually get loaded on that "page". I may go to settings and not need the account balances service.
The service won't call anything purely by being injected. You would still have to execute whatever you need to from the service after it has been injected. See my comment under your question regarding ngOnInit.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.