Brecht Baekelandt Brecht Baekelandt - 2 months ago 86
TypeScript Question

Passing data between components in Angular 2 with <router-outlet>

I am very new to Angular 2 and want to pass a bool from one component to another with

<router-outlet>


I understood for this I have to use a service.

Basically what I want is to set a bool in app.component.ts from another component front.component.ts, to expand and collapse a header in app.component.html.

This is what I have:

app.component.ts:

import { Component, OnInit } from "@angular/core";
import { HeaderService } from "./header.service";

@Component({
selector: "fandango-app",
templateUrl: "views/app.component.html",
providers: [HeaderService]
})

export class AppComponent implements OnInit {

headerCollapsed: Boolean = false;
headerService: HeaderService;

constructor(headerService: HeaderService) {
this.headerService = headerService;
}

ngOnInit() {
var self = this;
this.headerService.headerToggle.subscribe((headerCollapsed: Boolean) => () => {
self.headerCollapsed = headerCollapsed;
});
}
}


front.component.ts:

import { Component, AfterViewInit } from "@angular/core";
import { HeaderService } from "./header.service";

@Component({
templateUrl: "views/front.component.html",
styleUrls: ["content/front.component.css"]
})

export class FrontComponent implements AfterViewInit {

headerService: HeaderService;

constructor(headerService: HeaderService) {
this.headerService = headerService;
}

ngAfterViewInit() {
this.headerService.setHeader(false);
}
}


header.service.ts:

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

@Injectable()
export class HeaderService {

@Output() headerToggle = new EventEmitter<Boolean>();

constructor() {

}

setHeader(headerCollapsed: Boolean) {
this.headerToggle.emit(headerCollapsed);
}
}


app.routing.ts:

import { ModuleWithProviders } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";

import { FrontComponent } from "./front.component";
import { PricingComponent } from "./pricing.component";

const appRoutes: Routes = [
{ path: "", redirectTo: "front", pathMatch: "full" },
{ path: "front", component: FrontComponent },
{ path: "pricing", component: PricingComponent }
];

export const appRoutingProviders: any[] = [];

export const routes: ModuleWithProviders = RouterModule.forRoot(appRoutes);


app.module.ts:

import { NgModule } from "@angular/core";
//import { NgbModule } from "@ng-bootstrap/ng-bootstrap";
import { BrowserModule } from "@angular/platform-browser";
import { routes, appRoutingProviders } from "./app.routing";

import { AppComponent } from "./app.component";
import { FrontComponent } from "./front.component";
import { PricingComponent } from "./pricing.component";

import { AffixDirective } from "./affix.directive";

@NgModule({
imports: [
//NgbModule,
BrowserModule,
routes
],
declarations: [
AppComponent,
FrontComponent,
PricingComponent,
AffixDirective
],
providers: [
appRoutingProviders
],
bootstrap: [AppComponent]
})

export class AppModule { }


app.component.html:

<header [class.expanded]="!headerCollapsed" [class.collapsed]="headerCollapsed">
<div class="container">
<a href="/">
my app
</a>
</div>
</header>
<span>{{ headerCollapsed }}</span>
<router-outlet></router-outlet>


index.html:

<my-app id="app">
<div id="loader" class="container text-center">
<p>loading</p>
<div class="loader">
<span></span>
<span></span>
<span></span>
</div>
</div>
</my-app>


The problem is that it never steps into:

self.headerService.headerToggle.subscribe((headerCollapsed: Boolean) => () => {
self.headerCollapsed = headerCollapsed;
});


What am I doing wrong?

Mind again, I am very new to Angular2 and I don't know if this code is the best way to do it.

Answer

You shouldn't use @Output() or EventEmitter in a service. These are only for outputs on components and directives. @Output() in a service doesn't have any effect at all.

Use instead

headerToggle = new Subject<Boolean>();

In your case

headerToggle = new BehaviorSubject<Boolean>();

with

setHeader(headerCollapsed: Boolean) {
    this.headerToggle.next(headerCollapsed);
}

should fix your problem.

Also change

this.headerService.headerToggle.subscribe((headerCollapsed: Boolean) => () => {

to

this.headerService.headerToggle.subscribe((headerCollapsed: Boolean) => {

(remove ())

Comments