1

I have a Configuration service

@Injectable()
export class ConfigService {

    private config: PageConfig = new PageConfig({});

    public getConfig = (): PageConfig => {
        return this.config;
    }
}

var configInstance = null;

export function ConfigServiceFactory() {
    if (configInstance == null) {
        configInstance = new ConfigService();
    }

    return configInstance;
}

That uses a factory to return a single instance of the ConfigService, this is my "app.ts"

bootstrap(App, [
    HTTP_PROVIDERS,
    ROUTER_PROVIDERS,
    bind(ConfigService).toFactory(ConfigServiceFactory),
    provide(APP_BASE_HREF, { useValue: '/App/' }),
    provide(LocationStrategy, { useClass: PathLocationStrategy })
])
    .catch(err => console.error(err));

bootstrap(PageConfigComponent, [
    bind(ConfigService).toFactory(ConfigServiceFactory)
])
    .catch(err => console.error(err));

Sadly the Application is in 2 separate components (I cannot change this) and they both need to share specific configuration values, now I have a simple template with a binding to a string

@Component({
    selector: 'pagetitle',
    template: '<span>{{ pageConfig.Title }}ABC</span>',
    directives: [CORE_DIRECTIVES]
})

export class PageTitleComponent {
    public pageConfig: PageConfig = null;

    constructor(_configService: ConfigService) {
        this.pageConfig = _configService.getConfig();
    }
}

This binding is being initialized but its not changing the value even though the value stored in the ConfigService is being updated.

Daniel McAssey
  • 436
  • 5
  • 17

2 Answers2

1

This code copies the config from _configService once when PageTitleComponent is created. Besides that there is no relation at all between PageTitleComponent andConfigService`.

export class PageTitleComponent {
    public pageConfig: PageConfig = null;

    constructor(_configService: ConfigService) {
        this.pageConfig = _configService.getConfig();
    }
}

If you use an Observable then interested components can subscribe to changes.

@Injectable()
export class ConfigService {

    config: BehaviorSubject<PageConfig> = new BehaviorSubject<PageConfig>(new PageConfig({}));

    getConfig(): PageConfig => {
        return this.config;
    }

    // set a new config
    setConfig(PageConfig config) => {
        this.config.next(config);
    }
}
export class PageTitleComponent {

    constructor(_configService: ConfigService) {
      _configService.getConfig().subscribe(config => this.pageConfig = config);
    }
}

See also https://stackoverflow.com/a/36566919/217408 for a full example

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Hi there, doesn't seem to be working? http://plnkr.co/edit/Zsd8oUUNiwAFRa3CsLcv?p=preview - Is it possible this is an issue with Angular 2 RC.1 – Daniel McAssey Jun 06 '16 at 14:53
  • Interesting, I missed that one. If the value is emitted in one Angular application and received in the other, then the code emitting the new value obviously runs in a different zone than the one subscribing to it. Change detection doesn't recognize changes made by code that runs outside its zone. Therefore using `zone.run(() => ...)` makes Angular detect changes and update the view. See [**Plunker example**](http://plnkr.co/edit/IZqYuJ6DFo6g2tiW7FgH?p=preview) – Günter Zöchbauer Jun 06 '16 at 15:12
0

You could do the following:

let configService = new ConfigService();

bootstrap(App, [
  HTTP_PROVIDERS,
  ROUTER_PROVIDERS,
  provide(ConfigService, { useFactory => { configService) }), // <----
  provide(APP_BASE_HREF, { useValue: '/App/' }),
  provide(LocationStrategy, { useClass: PathLocationStrategy })
])
  .catch(err => console.error(err));

bootstrap(PageConfigComponent, [
  provide(ConfigService, { useFactory => { configService) }), // <----
])
  .catch(err => console.error(err));
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360