2017-01-28 2 views
5

Bin neu zu Angular2, aber ich habe bereits 30 + Komponente und Dienstleistungen und verwendet Input, Output, ChangeDetectorRef, Pipes. So ziemlich viel über Angular2 inzwischen wissen. Meine app.component.ts sieht aus wie dieseAngular2 - Übertragen von Daten außerhalb Router-Steckdose zu einer anderen Komponente

import { Component } from '@angular/core'; 
@Component({ 
    selector: 'soc', 
    template: ` 
     <header-block></header-block> 
     <router-outlet></router-outlet> 
    `, 
}) 
export class AppComponent { } 

Als ich meinen Kopfblock in jeder Seite müssen, damit ich es außerhalb Router-Block hinzugefügt, damit ich es nicht überall hinzufügen. Jetzt ist das Problem, das ich habe, den Wert der Variable im Kopfzeile-Block zu ändern, nachdem ich eine Handlung im Blick innerhalb des Fräserausgangs getan habe.

Zum Beispiel habe ich Menü, das für den Benutzer nur nach dem Login sichtbar sein wird.

{{ user_is_logged }} 
<ul class="nav navbar-nav navbar-right" *ngIf="user_is_logged == '1'"> 
    <li><a href="#" (click)="logout($event)">Logout</a></li> 
</ul> 

user_is_logged ist eine Variable, deren Wert am von localstorage immer in header.block.component.ts

user_is_logged:string = localStorage.getItem("logged"); 

Wenn der Benutzer nicht in dh user_is_logged ist nicht definiert für Hause angemeldet ist component.ts (wo login logic geschrieben wird), bitte ich den Benutzer, sich einzuloggen und nach erfolgreicher Anmeldung den Wert user_is_logged variabel und auch zu aktualisieren die localstorage Wert der Variablen zu aktualisieren und dann Änderungen Triggerung erfassen, indem der ChangeDetectionRef (cdr) und anschließend auf Benutzerprofil Routing

this.user_is_logged = "1"; 
localStorage.setItem('logged', '1'); 
this.cdr.detectChanges(); 
this.router.navigate(['u/'+user_id']); //user_id is from login response from server 

Das Problem ist, wenn ich das Benutzerprofil nach erfolgreicher Anmeldung den Wert {{user_is_logged erreichen }} wird niemals aktualisiert, auch wenn die Variable selbst verwendet wird oder der Wert von localStorage verwendet wird oder sogar die Erkennung angefordert wird.

Ist es möglich, dies auf diese Weise zu tun oder muss ich Header-Block zu jeder Seite separat hinzufügen? Bitte fragen Sie nach weiteren Informationen, wenn ich etwas verpasst habe.


EDIT ============>

So nach dem Durch Thema gehen, BehaviourSubject, AsyncSubject, ReplaySubject, Observable und was nicht, ich konnte einfach nicht bekommen arbeiten. Dies ist der letzte Code, den ich geschrieben habe:

home.page.component.ts (wo Login passiert und hat das Ereignis zu emittieren)

import { HomeService } from '../services/home.service'; 
// No observable or subject imported here. 

login() { 
    // Sending status 1 to HomeService 
    this.HomeService.changeStatus("1"); 
} 

home.service.ts (die importiert durch beide Komponente)

import { BehaviorSubject } from 'rxjs/BehaviorSubject'; 
// I imported Subject, BehaviourSubject, Observables but cant get it to work 

export class HomeService { 

    // This looked more reliable than Subject so used this; init with value "0" 
    public subjectStream = new BehaviorSubject<string>('0'); 


    constructor(
    ){ 
     this.subjectStream.subscribe(value => { 
      // Successfully logs value "1" sent by changeStatus below 
      console.log(value); 
     }); 
    } 


    changeStatus(value: any){ 

     // Gives value "1" when called by home.page.component.ts 
     console.log(value); 

     // Looks correct because it successfully sent value to construct 
     this.subjectStream.next(value); 

    } 

} 

header.block.component.ts

import { HomeService } from '../services/home.service'; 
// No observable or subject imported here also. 


constructor(
){ 
    this.HomeService.subjectStream.subscribe(value => { 
     // Logs value "0" at beginning but never logs value "1" 
     console.log(value); 
    }); 
} 

Mein Log

// logged by constructor when imported by header.block.component 
home.service.ts:31     0 

// logged by constructor of header.block.component itself 
header.block.component.ts:25  0 

// logged by constructor when imported by home.page.component (I think) 
home.service.ts:31     0 

// =================== 
// Login called here 
// =================== 

// logged by changeStatus after login after called by home.component 
home.service.ts:36     1 

// logged by constructor after getting event from changeStatus 
home.service.ts:31     1 

Was bin ich in header.block.component.ts fehlt? Wie der Wert erfolgreich innerhalb der home.service.ts aktualisiert wird, aber nie in den Header geht.

+0

Sounds wie http://stackoverflow.com/questions/35397198/how-can-i-watch-for-changes-to -localstorage-in-angular2/35397253 # 35397253 –

+0

Erstellen Sie einfach einen Service. Injizieren Sie es in beide Komponenten, lassen Sie beide einen Sender abonnieren (EventEmitter oder Subject, oder auch nur ein einfaches kleines Observer-Muster), das vom Dienst gehalten wird. Wenn man den anderen informieren muss, sagt man dem Dienst einfach "ein Ereignis ausstrahlen". Alles, was abonniert ist, wird es hören. Verwenden Sie Konstanten, um die Ereignisse nach Namen filtern zu können, oder verwenden Sie eine kleine Factory, um typisierte Ereignisse zu senden, wie auch immer Sie vorgehen möchten. Im Internet gibt es zahlreiche Beispiele, meist unter dem Titel "Daten zwischen Komponenten ohne Eltern-Kind-Beziehung senden". –

+0

FYI Ich mache genau dasselbe, was du tust; Ich habe einen Header, Router-Outlet und Fußzeile in den meisten meiner Apps. Der Router-Ausgang ändert sich, Header und Footer bleiben gleich, sie kommunizieren vollständig über diesen Sender-Service und es macht das Ganze so einfach. –

Antwort

1

Wenn Sie HomeService in Homepage und Header zur Verfügung stellen, erhalten Sie 2 Instanzen von HomeService. Wenn Sie einen Dienst freigeben möchten, geben Sie ihn nur einmal für die übergeordnete Komponente an. Wenn Sie eine einzelne Instanz mit Ihrer gesamten Anwendung teilen möchten, stellen Sie sie nur unter von AppModule

+0

Wenn ich HomeService von den Providern von @Component einer der beiden Komponenten entferne, dann bekomme ich diesen Fehler' Kein Provider für HomeService! ' Eigentlich ist das Problem, dass Homepage und Header nicht übergeordnete Kind sind. Wie Sie in Frage in meiner app.component.ts sehen können, habe ich zwei für Header und meine Homepage ist in so dass sie definitiv nicht Elternteil Kind aber mehr wie Geschwister oder Onkel-Neffe sind, seit Homepage ist Kind von

+0

Sie müssen es irgendwo bereitstellen. Sie sollten es nur einmal bereitstellen. Sie sollten es irgendwo zur Verfügung stellen, wo beide es injiziert bekommen. Dies bedeutet, wenn eine Komponente die übergeordnete Komponente der anderen Komponente ist, geben Sie sie bei der übergeordneten Komponente an. Wenn sie Geschwister sind, stellen Sie sie auf einem gemeinsamen Elternteil zur Verfügung. Wenn es ** nur ** im "AppModule" bereitgestellt wird, ist es immer ein anwendungsweiter Singleton. –

+0

Das einzige Elternteil, das sie beide haben, ist die app.component.ts selbst. Versuche es dort und aktualisiere dich. –

0

Wurde gebeten, dies zu veröffentlichen, ist es ein blanker Event/Betreff Service, um loszulegen. Ich benutze "notifier/notes/note", damit die Nomenklatur nicht mit "Ereignissen" und anderen Framework-API-Mechanismen verwechselt wird.

// Constant of named "notes" analogous to named events. 
// I always found it easier to have one event type with a "name", 
// rather than creating a specific typed event for every action. 
const Notes = { 
    HEADER_BUTTON_CLICKED : 'header_button_clicked' 
}; 

// Any component that wants to send data creates a new "Note" to send. 
// Just makes sure you know what all callbacks are getting. 
class Note { 
    constructor (name, data) { 
     this.name = name; // Should be from your Notes constant. 
     this.data = data; // Can be anything at all. 
    } 
} 

// You inject this service into any component that needs it. 
class NotifierService { 

    constructor() { 

     let Rx = require ('rx'); 
     // We'll use Subject here. 
     this.subject = new Rx.Subject (); 
    } 

    // You only subscribe if you want to hear notes. 
    subscribe (callback) { 
     // Subscribing component feeds in a callback. 
     // The return of this can be used to unsubscribe as well. 
     return this.subject.subscribe (b => callback (b)); 
    } 

    // Any component with access to this service can just create a note 
    // and send it to all subscribers to this service. 
    sendNote (note) { 
     // Component uses the service to emit a "note" with a 
     // named event and a payload. All subscribers hear it in the 
     // callbacks they subscribed with, and can filter on the name 
     // in the "note" to make sure it's the event they care about. 
     // This is pretty naive but should give the idea. 
     this.subject.onNext (note); 
    } 
} 
export { NotifierService } // Service to inject 
export { Note } // A useful type to send out to subscribers 
export { Notes } // Constant of event/note names. 

Typische Anwendungen:

import { NotifierService, Notes, Note } from './notifier.service'; 
... // inject in your constructor either TS or ES6 style... 

// I want to hear notes 
this.noteSvc.subscribe (b => this.myCallback (b)); 

// I want to send a note 
this.noteSvc.sendNote (new Note (Notes.HEADER_BUTTON_CLICKED, { btnName : 'Home' }); 

    // In the callback 
    myCallback (note) { 
    if (note.name === Notes.HEADER_BUTTON_CLICKED) { 
     console.log (note.data); // whatever the payload is 
    } 
    } 
Verwandte Themen