Sharing data between components in Angular 2 using the <router-outlet> technique

Having just started exploring Angular 2, I am eager to pass a boolean value from one component to another using <router-outlet>

After some research, it seems like the best approach is to utilize a service.

My aim is to toggle a boolean variable in app.component.ts from front.component.ts, triggering the expansion or collapse of a header in app.component.html.

This is my current setup:

app.component.ts:

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

@Component({
selector: "my-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 issue lies in not entering:

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

Can someone point out where I may have gone wrong?

Given my novice status with Angular 2, I'm open to learning if there's a better way to achieve this functionality.

Answer №1

Avoid using @Output() or EventEmitter in a service. These should be reserved for outputs on components and directives only. @Output() does not have any impact when used in a service.

Instead, consider using

headerToggle = new Subject<Boolean>();

In this specific scenario

headerToggle = new BehaviorSubject<Boolean>();

and then use

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

This approach should resolve the issue at hand.

Additionally, make sure to update

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

to

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

(remove ())

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issue in Angular2: Unable to load the templateUrl file for a component

I encountered an Unhandled Promise rejection: Failed to load error while working on my Angular 2 project: This is the snippet from my messages.component.js file: import { Component, OnInit } from "@angular/core" @Component({ moduleId: module.id, ...

Implementing Immer in Typescript

Recently, I've been exploring the possibility of integrating Immer into my React project that already utilizes Typescript. Unfortunately, I haven't been able to discover a clear guide on how to effectively employ Immer in conjunction with Typescr ...

Disable inline imports when implementing an interface in vscode by selecting the "Implement interface" option

When using TypeScript, if I perform an auto-fix on a class name by selecting "Implement interface", it will generate the methods with inline imports like this: getInbox(): Observable<import('../../model/Message').Interactions[]> { t ...

Significant bloat in main.js file detected in Angular 2 application compilation

I developed an application using <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="65040b02100904174806090c25554b554b565c">[email protected]</a>. The app is a transformation of a basic Angular 1 application. My conc ...

Monitor a universal function category

Trying to implement a TypeScript function that takes a single-argument function and returns a modified version of it with the argument wrapped in an object. However, struggling to keep track of the original function's generics: // ts v4.5.5 t ...

Executing the serve command in an Angular project necessitates a project definition, which unfortunately could not be located

An issue has arisen with the application I developed (angular2 nodejs). Upon attempting to open it, I encountered the following error message: The serve command needs to be executed within an Angular project, however a project definition could not be lo ...

Is it possible to target a specific element using Angular2's HostListener feature? Can we target elements based on their class name?"

Is there a way in Angular2 to target a specific element within the HostListener decorator? @HostListener('dragstart', ['$event']) onDragStart(ev:Event) { console.log(ev); } @HostListener('document: dragstart' ...

Error in WebStorm: Troubleshooting HTML file issue in Angular application

I encountered an error in WebStorm while working on a new project where I was testing a form. The issue only arises when I run ng serve, although no errors are reported and the application runs smoothly. To troubleshoot, I tried deleting my node_modules f ...

Creating a Worldwide Authorization Header with HttpClient Interceptors

I have implemented a global authorization header in my app using an interceptor to avoid declaring the authorization header in each get() function. However, I am facing an issue where the token is still being requested when I call the get() functions. Th ...

Invoking a function from a collection of mixed data types

I have established a mapping for a discriminated union consisting of different types, each linked to a corresponding function that uses a member of the union as a parameter: export interface Truncate { type: 'truncate' maxLength: number } ex ...

What is the best way to navigate between multiple pages in an Angular 7 application using ngIf?

In my Angular 7 app, I am facing an issue with switching between three different pages. While I have managed to switch between two of them successfully, the messages page loads in the documents section whenever I click on it. Even though I have attempted ...

What are the benefits of utilizing TypeScript declarations? How can you demonstrate their value with concrete examples?

I'm a bit confused about the use of declaration in TypeScript. It seems like the compiler doesn't compile it into the js file, so what is the purpose and advantage of using declaration? Can someone please explain this to me? ...

Declaration in Typescript for an array of strings that will be returned as a

I am facing an issue with my async function that is supposed to return either a single string or an array of strings. Here is the relevant code snippet: async getAllAnnotationTimes(): Promise<string> | Promise<string[]> { return aw ...

How to add Bootstrap and Font Awesome to your Angular project

After attempting to add Bootstrap and Font Awesome to my Angular application, I am encountering issues. I utilized the command npm install --save bootstrap font-awesome and included both libraries in the angular.json file as follows: "styles": ...

Points in an array being interpolated

I am currently working with data points that define the boundaries of a constellation. let boundaries = [ { ra: 344.46530375, dec: 35.1682358 }, { ra: 344.34285125, dec: 53.1680298 }, { ra: 351.45289375, ...

Is Angular equipped with named routes or states similar to UIRouter?

When working with AngularJS and ui-router, we define a state like this: .state('myState', { url: 'some-user-friendly-url' ... }) This allows us to easily specify the URL and name of the state. It simplifies navigation by letting ...

Unsure about Typescript object structures {} and []?

I am new to using lists and object lists in Typescript and I'm unsure of how they function. In the code snippet below, a few objects are created and some temporary values are assigned to them through a loop. However, my goal is to have the console log ...

tips for updating the input format of your ngx-datepicker

My goal is to receive a date input in the format yyyy-mm-dd, however, even after selecting the date correctly, I am receiving it in the 2019-07-08T12:16:10.000Z format. <input class="form-control" style="width: 48%;display: ...

Discovering if the array data is already present in Angular can be accomplished by using specific methods

Here is the snippet of code: data = [ { 'id': 'asdjxv', 'username': 'emma', }, { 'id': 'asqweja', 'username': 'adam', }, { ...

Eliminate a specific choice from a drop-down menu in an Angular application

I am implementing a feature where clicking on a button adds more select drop downs. I want to ensure that the selected options in these new dropdowns do not duplicate any already chosen options. Below is the code snippet used for the select drop down: < ...