Trigger parent Component property change from Child Component in Angular2 (akin to $emit in AngularJS)

As I delve into teaching myself Angular2, I've encountered a practical issue that would have been easy to solve with AngularJS. Currently, I'm scouring examples to find a solution with Angular2. Within my top-level component named App, there's a property applying a css class. Here is the HTML template for the component, where I intend to apply the css class using ngClass. The showMenu value is simply a boolean.

<div class="navigation" role="navigation">
    <ul>
        <li><a [routerLink]="'Home'">Home</a></li>
        <li><a [routerLink]="'Mail'">Mail</a></li>
        <li><a [routerLink]="'Friends'">Friends</a></li>
        <li><a [routerLink]="'Games'">Games</a></li>
    </ul>
</div>
<!-- below is where I wish to toggle the class -->
<div class="site-wrap" [ngClass]="{'slide-right': showMenu}">
    <div class="container-fluid">
        <div class="row nav">
            <top-navigation></top-navigation>
        </div>
    </div>

    <div class="container-fluid content-gradient">
        <div class="row">
            <div class="col-md-10">
                <router-outlet></router-outlet>
            </div>
            <div class="col-md-2">
                <contacts-list></contacts-list>
            </div>
        </div>
    </div>

    <div class="container-fluid footer">
        <footer-navigation></footer-navigation>
    </div>
</div>

Presented below is the basic Component Code for App:

export class App {

    showMenu: boolean = false;
    constructor() {
    }
    // Need a way to listen for the toggle
    toggleMenu():void {
        this.showMenu = !this.showMenu;
    }

}

The child component with the selector top-navigation has a method on a button that toggles the value of showMenu in the parent/top-level component. Here are some snippets of the code so far:

export class TopNavigation {

          constructor() {
            // Operations happening here
          }

          toggleMenu():void {
            // Aim to toggle the parent property through some form of $emit
          }
    }

Displayed below is a snippet of the template HTML for the Component:

<div class="col-xs-2 col-sm-1  hidden-md hidden-lg hamburger-menu">
    <button class="btn btn-default" (click)="toggleMenu()">&#9776;</button>
</div>

In the context of AngularJS, I typically used $scope.$emit on the toggleMenu function and had a corresponding $scope.$on in the parent to capture the event. Currently exploring EventEmitters in Angular2, but if anyone can provide a quick explanation or example, it would be greatly appreciated as this seems like a common task for Angular developers.

Answer №1

Utilizing a shared service that contains an EventEmitter property can help in this situation. The App component can subscribe to it to receive notifications when the corresponding event is triggered by the TopNavigation component.

  • Shared service

    @Injectable()
    export class MenuService {
      showMenuEvent: EventEmitter = new EventEmitter();
    }
    

    Don't forget to include the provider for the shared service in the bootstrap function to ensure the same instance is used throughout the application: `bootstrap(App, [ MenuService ]);

  • App component

    @Component({ ... })
    export class App {
      showMenu: boolean = false;
      constructor(menuService: MenuService) {
        menuService.showMenuEvent.subscribe(
          (showMenu) => {
            this.showMenu = !this.showMenu;
          }
       );
     }
    

    }

  • TopNavigation component:

    export class TopNavigation {
      constructor(private menuService: MenuService) {
        // Activities taking place here
      }
    
      toggleMenu():void {
        this.showMenu = this.showMenu;
        this.menuService.showMenuEvent.emit(this.showMenu);
      }
    }
    

Refer to this question for more information:

  • Delegation: EventEmitter or Observable in Angular2

Answer №2

Utilizing two-way binding is recommended for this scenario.

<top-navigation [(toggleMenu)]="showMenu"></top-navigation>

Alternatively, using one-way binding may also suffice depending on your specific needs.

<top-navigation (toggleMenuChange)="showMenu=$event"></top-navigation>
export class TopNavigation {
      @Output() toggleMenuChange: EventEmitter = new EventEmitter();

      // Enabling two-way binding
      @Input() toggleMenu:boolean = false;

      constructor() {
        // Additional functionality implemented here
      }

      toggleMenu():void {
        this.toggleMenu = !this.toggleMenu;
        this.toggleMenu.emit(this.toggleMenu);
      }
}

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

A guide to testing the mui Modal onClose method

When using material UI (mui), the Modal component includes an onClose property, which triggers a callback when the component requests to be closed. This allows users to close the modal by clicking outside of its area. <Modal open={open} onCl ...

Angular sets the required property only when the button is clicked

Is there a way to make a field required in Angular only when a button is clicked? Currently, the error message appears even before the user interacts with the field. I would like the error message "folder name is required" to only appear when the user cli ...

Customizing URL addresses based on webpack build configuration

Is there a way to parametrize the URL based on the webpack build profile? I'm referring to the URL used for services to fetch data from an API. For instance, in my Angular2 app: excerpt from package.json: "scripts": { "build-prod": "rimr ...

Setting up NextJs in Visual Studio Code with Yarn

When I used yarn create next-app --typescript to set up a TypeScript Next.js application with Yarn, everything seemed to be working fine with the command yarn run dev. However, Visual Studio Code was not recognizing any of the yarn packages that were added ...

Employ material-ui default prop conditionally

I am implementing a StepLabel component in material ui. Depending on the props passed to the parent, I may need to make changes to the icon property of the StepLabel: interface Props { customClasses?: ClassNameMap; customIcon?: ReactNode; } const MySt ...

After triggering an action, I am eager to make a selection from the store

To accomplish my task, I must first select from the store and verify if there is no data available. If no data is found, I need to dispatch an action and then re-select from the store once again. Here is the code snippet that I am currently using: t ...

React Native Expo Launch disregards typescript errors

While using Expo with Typescript, I've noticed that when I run the app with expo start or potentially build it, TypeScript errors are being ignored. Although Visual Studio Code still flags these errors, I can still reload the App and run it on my pho ...

Access a .docx file on my device by utilizing the Microsoft JavaScript API

In my current project, I am developing a Microsoft Word add-in using TypeScript, React, and the Word API. One of the key features of this add-in will allow users to open a document located on their computer, such as "C:\Test\Test.docx", with just ...

I am facing an issue with TypeScript as it is preventing me from passing the prop in React and Zustand

interface ArticuloCompra { id: string; cantidad: number; titulo: string; precio: number; descuento: number; descripcion: string; imagen: string; } const enviarComprasUsuarios = ({ grupos, }: { grupos: { [key: string]: ArticuloCompra & ...

The form data consistently replaces existing values with each new entry added

I am struggling to persist all the form values that are entered in my component using local storage. Despite setting and pushing the form values, I noticed that each time I push the data, it replaces the previously entered form data. My goal is to retain a ...

The behavior of Angular 4 CSS and JS changes upon refreshing the page

Every time I try to load a page with this particular script: this.router.navigateByUrl('/report-result/'+report.id); It appears that not all the CSS and JS files are being loaded properly. The bootstrap popovers don't show up, and some ele ...

What is the process for turning off deep imports in Tslint or tsconfig?

Is there a way to prevent deep imports in tsconfig? I am looking to limit imports beyond the library path: import { * } from '@geo/map-lib'; Despite my attempts, imports like @geo/map-lib/src/... are still allowed. { "extends": &q ...

I am looking to present a nested array within an array in a tabular format

This is the structure of my database: [{ "firstName": "Shaun", "salary": [ { "id":1, "rate": 250, }, { "id":2, "rate": 290, } ] },{ "firstName": "Julian", "salary": [ { "id":1, "rate": 750, ...

Typescript causing undefined React Router match issue

Currently, I am working on a basic eCommerce Proof of Concept using react and TypeScript. Unfortunately, I am facing an issue where I am unable to pass props to a product detail page or access the match containing the params. This is how my Routes pages a ...

Utilizing Shadow Root and Native Web Components for Seamless In-Page Linking

An illustration of this issue is the <foot-note> custom web component that was developed for my new website, fanaro.io. Normally, in-page linking involves assigning an id to a specific element and then using an <a> with href="#id_name&quo ...

Android encountered an unknown error while trying to access the URL, resulting in an HTTP failure response with a status

My Ionic app runs perfectly fine on iOS, but when I try to run it on Android, I encounter the following error: Http failure response for (unknown url): 0 Unknown Error https://i.stack.imgur.com/8EFna.png I have CORS enabled on the server side and it wor ...

When Electron combines with Angular 4, the expected two-way data binding functionality fails to work

Each time the UI needs updating, developers are required to use the zone.run() method, which is not ideal as it adds repetitive code and lacks intuitiveness. Our main dependencies include: "dependencies": { "@angular/animations": "4.0.0", "@angular/com ...

Angular 2 form controls featuring custom display names and unique values

As I work on developing a form, I have encountered the need to display something different than the content itself. Here's what I currently have in my code: <ion-label>Rate</ion-label> <ion-input text-right detail-push formContro ...

Executing a function to erase the stored value in local storage during an Angular unit test

Looking to verify whether the localStorage gets cleared when I execute my function. Component ngOnInit() { // Logging out when reaching login screen for login purposes this.authService.logout(); } authService logout() { // Removing logged i ...

Potential null object in React/TypeScript

Encountering a persistent error here - while the code functions smoothly in plain react, it consistently throws an error in typescript stating "Object is possibly null". Attempts to resolve with "!" have proved futile. Another error logged reads as follow ...