Angular component: The selected property is not appearing set to false on the first click when using @

I am currently working on developing a set of accordion components. My goal is to have only one accordion open at a time out of the three available. Essentially, if one accordion is open and I click on another one, the open accordion should collapse.

At the moment, I am able to toggle the accordions to open and close, but I am struggling to properly 'select' them to apply the "collapse" class when they are not the currently selected one. The select input seems to be false on the first click (although it appears differently in Augury).

In my accordion-group.component.ts file:

import { AccordionComponent } from './../accordion/accordion.component';
import { Component, Input  } from '@angular/core';

@Component({
  selector: 'app-accordion-group',
  templateUrl: './accordion-group.component.html',
  styleUrls: ['./accordion-group.component.css']
})
export class AccordionGroupComponent {
  @Input() measures;
  selected

  select(i){
    this.selected = i;
  }
}

For the accordion-group.component.html:

<app-accordion
*ngFor="let item of items; let i = index"
[item]="item"
[selected]="i === selected"
(click)="select(i)">
</app-accordion>

Moving on to the accordion.component.ts file:

import { Component, Input } from "@angular/core";

@Component({
  selector: "app-accordion",
  templateUrl: "./accordion.component.html",
  styleUrls: ["./accordion.component.css"]
})
export class AccordionComponent {
  @Input() item;
  @Input() index;
  @Input() selected //this needs to receive true on selected component on click

  expand: string = "";
  isOpen = false;

  handleExpansion() {
    console.log(this.selected) //logs false on first click
    this.isOpen = !this.isOpen;

    this.isOpen ? (this.expand = "expand") : (this.expand = "collapse");
  }
}

And finally, for accordion.component.html:

<div
(click)="handleExpansion()"
class="accordion noHighlight {{expand}}">
</div>

Answer №1

The reason for your current experience is due to the bubbling up of browser DOM events. In this case, the click handler in the AccordionComponent will be executed before the one in the AccordionGroupComponent.

There are several ways to achieve what you intend to do, and I have created a quick Plunker example showcasing one approach.

In essence, the group decides which accordion is expanded:

@Component({
    selector: 'app-accordion-group',
    template: `
        <app-accordion *ngFor="let accordion of accordions" [title]="accordion.title"
            [isExpanded]="accordion === expandedAccordion"
            (expandClick)="processExpandClick(accordion, $event)">
            <p>{{ accordion.description }}</p>
        </app-accordion>
    `
})
export class AccordionGroupComponent {
    @Input() accordions: Accordion[];

    expandedAccordion: Accordion = null;

    processExpandClick(accordion: Accordion, isExpanded: boolean) {
        this.expandedAccordion = isExpanded ? accordion : null;
    }
}

Additionally, the accordion emits events when expanding or collapsing, enabling the group to control the expand/collapse behavior:

@Component({
    selector: "app-accordion",
    template: `
        <div class="accordion" [class.expanded]="isExpanded">
            <div (click)="handleClick()">
                <span *ngIf="!isExpanded">+</span>
                <span *ngIf="isExpanded">-</span>
                {{ title }}
            </div>
            <div class="accordion__content">
                <ng-content></ng-content>
            </div>
        </div>
    `,
    styles: [`
        .accordion__content {
            height: 0;
            overflow: hidden;
        }

        .expanded .accordion__content {
            height: auto;
        }
    `]
})
export class AccordionComponent {
    @Input() title;
    @Input() isExpanded = false;
    @Output() expandClick = new EventEmitter<boolean>();

    handleClick() {
        this.expandClick.emit(!this.isExpanded);
    }
}

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

Building Angular 2 - Generate Multiple Sections in HTML with the Click of a Button

<div class="schedule-time"> <span>Include Schedule Time <span class="adr" (click)="AddNewSchedule()">+</span></span> ........ </div> <div *ngFor = "let i of OpenNewSchedule"> <div class= ...

Is your Angular5 service failing to transmit data?

I have two components in my code, A and B. Component A contains a form with data that I want to send to component B. However, it seems like component B is not receiving any data. Here is the code for Component A: import { MyService } from 'path/my ...

An intelligent TypeScript editor that highlights all compilation errors across the entire project, not just within currently open files

After experimenting with various development environments including Eclipse with Codemix plugin, Palantir TS plugin, and Wild Web Developer plugin, as well as VisualStudio Code, I found that they only display errors on open files. Is there an IDE available ...

Tips for combining two ReadonlyArrays in Typescript?

What is the best way to concatenate two arrays in typescript when they are ReadonlyArrays? Take a look at the following example: const strings1: ReadonlyArray<string> = ["foo"]; const strings2: ReadonlyArray<string> = ["bar"]; const allString ...

Step-by-step guide for deploying an Angular 2 CLI app on GitHub

As a front-end engineer, I have limited experience with deployment. Currently, I am working on my pet project using angular-cli. What is the best way to deploy it on GitHub Pages? Are there any other straightforward methods for deployment? ...

Guide on integrating third party jquery plugin with Angular 7

Hey there! I've been working on integrating a third-party jQuery plugin into my Angular 7 app. Here's what I've done so far: I added the file locations in angular.json like this: "scripts": [ "node_modules/jquery/dist/jquery.m ...

Angular 2.0 encountered an unexpected value from the module 'AppModule' which appears to be an '[object Object]'

Every time I attempt to load my angular version 2.0 application, I encounter the following error: (index):21 Error: Error: Unexpected value '[object Object]' imported by the module 'AppModule' import { ModuleWithProviders } from ' ...

Exploring the optimal procedures to asynchronously request an external API in Node.js using TypeScript

When handling a POST API request in a Node.js application built using TypeScript, it's necessary to make a call to an external API. This external API operates independently and must run in the background without impacting the response time. How can t ...

Event to listen to for rendering dynamically updated data from a service

Currently, I am in the process of developing an Angular 4 component that will be responsible for displaying data provided by an Angular 4 service. Given that the data is subject to frequent changes, I am looking to implement a mechanism that will ensure th ...

Controller property not being updated by directive

I have developed a custom directive to identify when the enter key is pressed within a text box. Here's the implementation of the directive: import { BookmarkService } from "../services/bookmarkService"; import { qlik, QlikBookmarkInfo } from "../qli ...

Ensuring typescript req.user in Passport JS is always defined: Best practices

When utilizing Passport JS, the req.user within the route is considered potentially undefined. However, the middleware prior to my route method ensures that this scenario does not occur. How can I convey this information to TypeScript? Object may be &apos ...

Setting up an Angular proxy for Server prod: A step-by-step guide

Exploring a new approach in my Angular front end app, I aim to conceal the API URL from the browser's network. For example, instead of directly calling api.url.dz/login, I wish to call front.url.dz/login on the front end and then redirect it to api.ur ...

Error encountered in TypeScript Yarn application during download process: SyntaxError: Unforeseen symbol '.'

Today marks my first experience using yarn for applications, and unfortunately, I've encountered a frustrating issue: SyntaxError: Unexpected token '.' at wrapSafe (internal/modules/cjs/loader.js:915:16) at Module._compile (internal/ ...

A guide on exporting the data type of a computed property in Vue3

I'm facing a challenge with my Vue3 component that interacts with GraphQL requests. After receiving a large JSON response, I utilize a computed property to extract the necessary value. Now, I aim to pass this extracted value as a prop to a child compo ...

Angular/NGRX disrupts the result

Currently, I am working on a piece of code where my main focus is to add a reducer to the module. Here's the snippet: import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { St ...

Error: The 'contains' property is not available for type 'never'

I'm facing a persistent error that is making my file display in red. I attempted to include types while using useRef(null), but the error continues to persist. Could it be possible that I am assigning incorrect types? const dropdownRef = useRef(null) ...

Oops, it seems like there was an issue with NextJS 13 Error. The createContext functionality can only be used in Client Components. To resolve this, simply add the "use client" directive at the

**Issue: The error states that createContext only works in Client Components and suggests adding the "use client" directive at the top of the file to resolve it. Can you explain why this error is occurring? // layout.tsx import Layout from "./componen ...

The culprit behind Angular 11 app error: Unidentified router outlet triggering 'No routes match' issue

In my Angular 11 application, I am utilizing a named router-outlet. The setup in my app.component.html file looks like this: <ng-container *ngIf="showGeneric"> <router-outlet name="general"> </router-o ...

Establish a connection between two pre-existing tables by utilizing the Sequelize framework

I have two tables already set up (User and PaymentPlan), but they were not initially linked together. PaymentPlan.ts import { DataTypes, Model } from "sequelize"; import { sequelize } from "./DBConnections/SequelizeNewConnection"; exp ...

Angular ng-bootstrap modal dialog: retrieving closeResult value before proceeding with execution

I've been working on an Angular project using ng-bootstrap (currently version 5), and I've successfully implemented a modal component that can be called from multiple components with unique title and message inputs. However, I'm encounterin ...