typescript - angular 2 - ändra gränssnitt i global tjänst genom komponent och uppdatera ändrat gränssnitt i en annan


Jag leker med Angular 2. Jag vill bygga en global tjänst som håller ett gränssnitt. Detta gränssnitt kan ändras genom en HeaderComponent. Efter att användaren ändrat gränssnittet genom HeaderComponent har gränssnittet också ändrats i en annan ChildComponent. Därför arbetade jag med detta svar som jag hittade på Stack Overflow.

Säg att jag har ett gränssnitt och 2 olika klasser. Var och en av dessa klasser håller en olika typ av gränssnittet.

MinGränssnitt

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",
    };
}

En global tjänst implementerar detta gränssnitt.

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);
                }
            }
        }
    }
}

Nu är HeaderComponent som är implementerad som direktiv i 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 { }

kan ändra gränssnittet via ett urvalsfält:

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);
    }
}

Hittills så bra. Efter att jag ändrat gränssnittet genom min HeaderComponent vill jag att gränssnittet också ändras i en annan ChildComponent som kommer att visas genom <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;
    }
}

Problemet är att ändringen av gränssnittet genom HeaderComponent fungerar, men gränssnittet ändras inte för ChildComponent. Funktionen changeInterface(interface: MyInterface) i min ChildComponent anropas inte ens. Här arbetar användaren med:

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

för ChildComponent. Men om jag gör det får jag ett fel i min Sublime-redigerare: "Parametern 'interface' har implicit typen 'any'." Så vad gör jag fel? Vad saknar jag här?

Här kan du se det på Plunker.

Svar #1

Felet i din redigerare

»Parametern 'interface' har implicit typen 'any'.«

är eftersom du har en strikt TypeScript-regel som förhindrar att tsc kompilerar din kod. Ändra antingen konfigurationen genom att gå till tsconfig.json och stäng av noImplicitAny-flaggan:

"noImplicitAny": false

Eller lägg till typ till ditt gränssnitt i din subscribe-callback:

globalService.interfaceChanged.subscribe((_interface: MyInterface) 
  => this.changeInterface(_interface));