2

I am playing around with angular 2. I want to build a global service that holds an interface. This interface can be changed through a HeaderComponent. After the user changed the interface through the HeaderComponent the interface has also been changed in another ChildComponent. Therefor I worked with this answer found on stack overflow.

Let's say I have an interface and 2 different classes. Each of these classes are holding a different type of the interface.

MyInterface

export interface MyInterface {
    key: string,
}

ClassA

import { MyInterface } from './interfaces/my-interface';
export class ClassA {
    type = "A";
    _interface: MyInterface = {
        key: "value1",
    };
}

ClassB

import { MyInterface } from './interfaces/my-interface';
export class ClassB {
    type = "B";
    _interface: MyInterface = {
        key: "value2",
    };
}

A global service is implementing this interface.

GlobalService

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

import { ClassA } from './classes/class-a';
import { ClassB } from './classes/class-b';
import { MyInterface } from './interfaces/my-interface';

@Injectable()
export class GlobalService {

    public interfaceChanged: EventEmitter<MyInterface>;
    _interface: MyInterface;

    interfaceList: string[] = [];

    interfaces = [
        new ClassA(),
        new ClassB()
    ];

    selectedInterface: string;

    constructor() {
        this.interfaceChanged = new EventEmitter<MyInterface>();
        for (var i = 0; i < this.interfaces.length; i++)
            this.interfaceList.push(this.interfaces[i].type);
        this.changeInterface(this.interfaceList[0]);
    }

    changeInterface(_interface: string): void {
        if (this.interfaceList.includes(_interface)) {
            this.selectedInterface = _interface;
            for (var i = 0; i < this.interfaces.length; i++) {
                if (this.interfaces[i].type == this.selectedInterface) {
                    this._interface = this.interfaces[i]._interface;
                    this.interfaceChanged.emit(this.interfaces[i]._interface);
                }
            }
        }
    }
}

Now the HeaderComponent which is implemented as directive in app.component.ts

app.component.ts

import { HeaderDirective } from './directives/header';
import { FooterDirective } from './directives/footer';

@Component({
  selector: 'my-app',
  template: `
    <my-header></my-header>
    <div class="container">
      <router-outlet></router-outlet>
    </div>
    <my-footer></my-footer>
  `,
  styleUrls: [ ],
  directives: [HeaderDirective, FooterDirective, ROUTER_DIRECTIVES]
})
export class AppComponent { }

is able to change the interface through a select field:

import { Component } from '@angular/core';
import { MyInterface } from './interfaces/my-interface';
import { LanguageService } from './services/global-service';

@Component({
    selector: 'my-header',
    template: `
      <select (change)="change($event.target.value)">
        <option *ngFor=" let _interface of interfaceList ">{{ _interface }}</option>
      </select>
    `,
})
export class HeaderComponent {

    selectedInterface: string;
    interfaceList: string[];
    _interface: MyInterface;

    constructor(private globalService: GlobalService) {
        this.selectedInterface = this.globalService.selectedInterface;
        this.interfaceList = this.globalService.interfaceList;
        this._interface = this.globalService._interface;
    }

    change(_interface: string) {
        this.globalService.changeInterface(_interface);
    }
}

So far so good. After I changed the interface through my HeaderComponent I want that the interface also be changed in another ChildComponent that is going to be displayed through <router-outlet></router-outlet>

import { Component, EventEmitter } from '@angular/core';
import { GlobalService } from './services/global-service';
import { MyInterface } from './interfaces/my-interface';

@Component({
  selector: 'my-child',
  template: `
    <p>Test: {{ _interface.key }}</p>
  `,
})
export class ChildComponent {

    private _interface: MyInterface;

    constructor(private globalService: GlobalService) {

        this.globalService.interfaceChanged
                          .toPromise()
                          .then(_interface => {
                              this.changeLanguage(_interface);
                          })
                          .catch(err => {
                              console.log(err);
                          });
    }

    changeInterface(_interface: MyInterface) {
        this._interface = _interface;
    }
}

The problem is that the change of the interface through the HeaderComponent is working but the interface doesn't change for the ChildComponent. The changeInterface(interface: MyInterface) function in my ChildComponent isn't even called. Here the user is working with:

...
constructor(globalService: GlobalService) {
    globalService.interfaceChanged.subscribe(_interface => this.changeInterface(_interface));
}
...

for the ChildComponent. But if I do so there is an error within my sublime editor: "Parameter 'interface' implicitly has an 'any' type." So what am I doing wrong? What am I missing here?

Here you can see it on Plunker.

Community
  • 1
  • 1
user2741109
  • 121
  • 13

1 Answers1

2

The error in your editor

"Parameter 'interface' implicitly has an 'any' type."

is because you have strict TypeScript rule that prevents tsc from compiling your code. Either change the config by going to tsconfig.json and turn off noImplicitAny flag:

"noImplicitAny": false

Or add type to your interface in your subscribe callback:

globalService.interfaceChanged.subscribe((_interface: MyInterface) 
  => this.changeInterface(_interface));
Harry Ninh
  • 16,288
  • 5
  • 60
  • 54
  • Hey, I am now trying to handle this by using a custom pipe. Would you please take a look at it. I am stuck already. [Plunker](https://plnkr.co/edit/SuMywz7oxsy5iM3DqOAD?p=preview) – user2741109 Jul 31 '16 at 16:58
  • Hey if it's not very related to this question, I think it's better for you to ask new question. It will reach more minds that way :) – Harry Ninh Jul 31 '16 at 23:27
  • Okay, I opened a new [question](http://stackoverflow.com/questions/38692577/angular2-use-global-service-through-a-custom-pipe) – user2741109 Aug 01 '16 at 06:50