Altering a public variable of a component from a sibling component

Within my application, I have two sibling components that are being set from the app.component:

<my-a></my-a>
<my-b></my-b>

The visibility of <my-a> is determined by a public variable in its component:

@Component({
  moduleId: module.id,
  selector: 'my-a',
  templateUrl: `<div *ngIf="visible">Hello World</div>`
})

export class MyAComponent {
    public visible = false;
}

I want to update the value of visible after clicking on an element within <my-b>:

@Component({
  moduleId: module.id,
  selector: 'my-b',
  templateUrl: `<div (click)="onClick()">Click Me</div>`
})

export class MyBComponent {
    onClick() {
        // logic goes here
    }
}

How can I change visible = true in <my-a> from <my-b>? Should this functionality be handled in the parent app.component?

UPDATE

After receiving some feedback, I was able to achieve the desired behavior using a few lines of jQuery:

@Component({
  moduleId: module.id,
  selector: 'my-b',
  templateUrl: `<div (click)="onClick('my-a')"></div>`
})

export class MyBComponent {
    onClick(element) {
        $(element).show(); // or hide() or toggle() or different actions
    }
}

Although this approach works well and can be easily scaled for multiple elements, I am concerned about whether using jQuery in Angular2 is considered good practice.

Answer №1

One way to achieve this is by utilizing the EventEmitter and Input in Angular.

Component X:

@Component({
  moduleId: module.id,
  selector: 'my-x',
  templateUrl: `<div *ngIf="isVisible">Hello World</div>`
})

export class MyXComponent {
    // listen for input variable passed by parent
    @Input() isVisible;
}

Component Y:

@Component({
  moduleId: module.id,
  selector: 'my-y',
  templateUrl: `<div (click)="onClicked()">Click Me</div>`
})

export class MyYComponent {
    // create EventEmitter to emit when onClicked method is called
    @Output() isVisible = new EventEmitter();
    onClicked() {
        this.isVisible.emit();
    }
}

And in the parent component:

@Component({
  moduleId: module.id,
  selector: 'parent',
  // pass isVisible variable to MyXComponent and listen for onClicked event from MyYComponent
  templateUrl: `<my-x [isVisible]="isVisible"></my-x>
                <my-y (onClicked)="toggleVisibility()"></my-y>`
})

export class ParentComponent{
    private isVisible: boolean = false;
    // toggle visibility based on emitted event from MyYComponent
    toggleVisibility() {
    if (this.isVisible === false) {
    this.isVisible = true;
    } else {
        this.isVisible = false;
        }      
    }
}

In more complex scenarios, consider using a shared service instead.

Answer №2

The concept is divided into three segments, all revolving around the main app.component. It can be broken down into specific tasks:

  1. The need to allow external sources to alter visibility. This can be achieved using an Input property
  2. Featuring a button whose purpose is to trigger an action on a different component. Therefore, it requires an Output property (in the form of an EventEmitter)
  3. The parent object can then connect to 's Output in order to set a variable that binds to 's Input.

Input property within MyAComponent

import { Component, Input } from '@angular/core';
@Component({
  moduleId: module.id,
  selector: 'my-a',
  template: `<div *ngIf="visible">Hello World</div>`
})
export class MyAComponent {
    @Input() visible: boolean = false;
}

This is how the parent component's HTML would look like to configure this:

<my-a [visible]="aVisibility"></my-a>

Output property in MyBComponent

import { Component, Output, EventEmitter } from '@angular/core';
@Component({
  moduleId: module.id,
  selector: 'my-b',
  template: `<div (click)="onClick()">Click Me</div>`
})
export class MyBComponent {
    @Output() makeVisible: EventEmitter<void> = new EventEmitter<void>();

    onClick() {
        this.makeVisible.emit();
    }
}

To listen to changes as a parent component, the HTML structure should resemble this:

<my-b (makeVisible)="makeAVisible()"></myb>

Integration through the parent component

import { component } from '@angular/core';
@Component({
    moduleId: module.id,
    selector: my-app,
    template: `
      <my-a [visible]="aVisibility"></my-a>
      <my-b (makeVisible)="makeAVisible()"></myb>
    `
})
export class MyApp {
    private aVisibility:boolean = false;

    makeAVisible() : void {
        this.aVisibility = true;
    }
}

Additional Information

This code has not been tested, so there may be typos and errors present. Additionally, if communication between components becomes complex, using a shared Service might be preferable. However, for a simple scenario like this, utilizing the parent component should suffice.

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

Failure to Generate stats.json File When Building Angular 6 with --stats-json Flag

Currently, I am facing an issue with generating the stats.json file for my Angular 6 application. Despite trying a few different methods, the file is simply not being created. It seems that my system specifically requires "npm run" before every Angular CLI ...

React TypeScript - Module not found

Organizational structure: src - components - About.tsx In an attempt to optimize performance, I am experimenting with lazy loading: const About = React.lazy(() => import('components/About')); However, Visual Studio Code is flagging &ap ...

Enroll in a stream of data while iterating through a loop in an Angular application

I encounter a situation where I must subscribe to an Observable, iterate through the response, and then subscribe to another Observable using data from the initial Observable. getTasks(taskType: Observable<any>): void { taskType // Subscribing ...

Angular2's customer filter pipe allows for easy sorting and filtering of

Check out the component view below: <h2>Topic listing</h2> <form id="filter"> <label>Filter topics by name:</label> <input type="text" [(ngModel)]="term"> </form> <ul id="topic-listing"> <li *ngFo ...

How to make a node application run as an executable within an NX workspace

The structure of an NX workspace really caught my attention, which led me to start using it for a new CLI project I was working on. I began by setting up a @nrwl/node:application, but I'm currently facing some issues trying to make it executable. I ...

Unable to open modal window in Angular 14 micro-frontend application

I've been working on a micro front end project and running into some issues with opening modal popup windows. I've tried both the Angular material and bootstrap approaches, but ran into problems with both. With Angular material, the popup window ...

Is there a way to dynamically transfer projected content to child components without using <ng-content> for rendering?

Let's say I have a <hook> component that dynamically creates a child, how can I transfer the content (which Angular would usually render inside a <ng-content></ng-content> in the hook's template) as ng-content to that child comp ...

What is the best way to retrieve a value from an array of objects containing both objects and strings in TypeScript?

Consider this scenario with an array: const testData = [ { properties: { number: 1, name: 'haha' } , second: 'this type'}, ['one', 'two', 'three'], ]; The goal is to access the value of 'second&ap ...

The 'ngForOf' directive cannot be bound to 'div' element as it is not recognized as a valid property

Encountering an issue with adding an ngFor directive on a div, which is causing a warning and preventing my HTML from rendering properly. I experimented with using *ngFor on various elements like <li>, <tr>, and <span>, but kept getting ...

Updating the page dynamically in React/Redux by making API calls based on user submissions

My current task involves calling an API with Redux, triggering the call based on a form submission. If the query is empty, it should return all lists; otherwise, it should only return lists that match the query. // List.tsx import React, { useEffect, useS ...

Prevent Duplicate Service Instances in Angular

After doing some thorough research online, I've identified the root of my issue: multiple instances of a particular service are being created. I need assistance in pinpointing and rectifying this problem within my code. The secondary service is depen ...

Best Practices for TypeScript and React: How to Handle Component State for Mounted Components

One technique to avoid calling .setState() on an unmounted component is by using a private property like _isMounted to keep track of it, as discussed in a blog post. I have implemented this method as follows: class Hello extends React.PureComponent{ _isM ...

Error message "The result of this line of code is [object Object] when

Recently, I encountered an issue while retrieving an object named userInfo from localStorage in my Angular application. Despite successfully storing the data with localStorage.setItem(), I faced a problem when attempting to retrieve it using localStorage.g ...

Preventing recursive updates or endless loops while utilizing React's useMemo function

I'm currently working on updating a react table data with asynchronous data. In my initial attempt, the memo function doesn't seem to be called: export const DataTableComponent = (props: State) => { let internal_data: TableData[] = []; ...

Encountering an issue when attempting to attach an event listener to the entire document

I need help troubleshooting an issue with a function that is supposed to perform certain operations when the scrollbar is moved. I attached an event listener to the document using an ID, but it's resulting in an error. ERROR Message: TypeError: Canno ...

While attempting to send a GET Request in Angular, access to XMLHttpRequest has been denied due to CORS policy restrictions

I am attempting to establish a GET method for my PHP API. Here is the code snippet I am using: export class PerfilComponent { perfil: any; constructor(private http: HttpClient) { } ngOnInit() { const token:string | null = localStorage.getItem(&ap ...

How to globally install electron using NPM on Ubuntu

Encountering an issue while trying to resolve this problem. Upon installing electron globally using NPM, the following error is displayed: ole@mki:~/angular-electron$ sudo npm install electron -g /usr/bin/electron -> /usr/lib ...

Having difficulties utilizing React Syntax Highlighter in Next.js 13 with Sanity version 3

Hello there, I've encountered a problem with my project while using Sanity v3 and React Syntax Highlighter. Initially, I had success displaying my code in the browser by utilizing the Refactor library after following a tutorial on the Code Input by Sa ...

Ways to verify that the Google Analytics code is functioning properly within an Angular 2 application

I'm just getting started with Google Analytics and I'm attempting to integrate it into my Angular 2 project. Here's how I've set it up: app.component.ts import { Component } from '@angular/core'; import {Router, NavigationEn ...

Using Bootstrap 4 Datatablejs within an Angular4 CLI project

Just finished developing a web application using Angular 4 and Angular CLI tool. Currently, I am trying to display a table with DataTableJs on one of the pages of my app. However, the styling is not coming out as expected. https://i.stack.imgur.com/H5IIT ...