What is the best way to make one element's click event toggle the visibility of another element in Angular 4?

Recently diving into Angular, I'm working on a feature where users can toggle the visibility of a row of details by simply clicking on the item row. The scenario involves a table displaying log entries, each with a hidden row underneath containing specific information. Upon clicking a log entry row, the details row should appear or disappear.

Initially, I handled this within the event handler by manipulating the DOM to adjust the style of the details row. However, considering Angular's best practices, I found a more suitable solution after some exploration:

The key HTML snippet:

<tbody>
    <ng-container *ngFor="let entry of log; let i=index">
        <tr class="log-entry" (click)="displayRow[i] = !displayRow[i]">
            <td class="datetime">{{entry.datetime}}</td>
            <td class="actor">{{entry.actor}}</td>
            <td class="summary">{{entry.summary}}</td>
        </tr>
        <tr class="details" [style.display]="displayRow[i] ? 'table-row' : ''">
            <td colspan="3">
                <pre>{{entry.details}}</pre>
            </td>
        </tr>
    </ng-container>
</tbody>

And here's the respective code:

import { Component, OnInit } from '@angular/core';
import { LogEntry } from '../log';
import { LogService } from '../log.service';

@Component({
  selector: 'app-log',
  templateUrl: './log.component.html',
  styleUrls: ['./log.component.styl']
})
export class LogComponent implements OnInit {
  log: LogEntry[]

  // An array of booleans used in the template to track toggled detail rows
  displayRow: boolean[] = []

  constructor(private logService: LogService) { }

  ngOnInit() {
    this.logService
      .getLog()
      .then(this.onLogUpdated)
      .catch(this.onLogUpdateError)
  }

  // Event handlers

  private onLogUpdated = (log: LogEntry[]) => {
    console.debug("Redrawing log")

    this.displayRow = log.map((x) => false)
    this.log = log

    console.log(this.displayRow)
    console.log(this.log)
  }

  private onLogUpdateError = (error) => {
    console.error("Error when trying to get log from log service")
    console.error(error)
  }
}

Although I'm effectively managing the state of the details row with an array of booleans, I wonder if there's a cleaner and more Angular-friendly way to achieve this behavior solely within the template. Any insights?

Answer №1

Upon further exploration of the Angular 4 guide, I came across a more elegant method for handling details rows. This technique involves using a template reference variable to tag the row and then invoking a function to hide it:

<ng-container *ngFor="let entry of logToday; let i=index">
<tr class="log-entry" (click)="toggleRow(details)">
    <td class="datetime">{{entry.datetime}}</td>
    <td class="actor">{{entry.actor}}</td>
    <td class="summary">{{entry.summary}}</td>
</tr>
<tr #details class="details">
    <td colspan="3">
        <pre>{{entry.details}}</pre>
    </td>
</tr>
</ng-container>

Although a component code function is still needed:

// Toggles the visibility of a table row
toggleRow(row) {
  if (row.style.display == '') {
    row.style.display = 'table-row'
  }
  else {
    row.style.display = ''
  }
}

Despite this requirement, this approach presents a cleaner solution compared to my initial method.

Important note: The toggle function is designed with the assumption that the details row is initially hidden.

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

Iterating through an object using the forEach method (uncommon practice)

Greetings, I have the following object: data = { name: undefined, age: undefined, gender: undefined }; I am looking to iterate through each key and value pair in this object and perform an action. Here is my attempt: this.data.forEach((item: ...

The error message "The file 'environment.ts' is not located within the specified 'rootDir' directory" was encountered during the Angular Library build process

When attempting to access the environment variable in an Angular 9 library, I encountered an error during the library build process. Here is how it was implemented: import { EnvironmentViewModel } from 'projects/falcon-core/src/lib/view-models/envir ...

Having trouble accessing the theme in a styled component with @emotion/styled

https://i.stack.imgur.com/zHLON.png I've been using @emotion/react for theming and successfully injected the theme into it. I can access the theme using useTheme within components, but I'm facing some difficulties in accessing the theme within s ...

As I iterated over the Vehicles API data, I encountered an issue while trying to access specific Vehicle information. I received an error message stating "Cannot read property 'id' of undefined

Exploring the realms of Angular, with some experience in older versions, I find myself faced with a challenge involving two APIs - "/vehicles" and "/vehicle/{id}". The process involves fetching data from "/vehicles", iterating through it to match IDs, the ...

The Vue data retrieved from an API using onMounted() is not initially showing up in the DOM. However, it magically appears after I make changes to the template

Hello and thank you to those taking the time to read this. I am new to Vue, so I may be overlooking something obvious here, but after being stuck for several days, I am reaching out for help. In my SFC file, I have an onMounted function fetching data from ...

Erase the destination pin on Google Maps

I am currently working on a project that involves displaying hit markers on google maps along with a route from start to finish. Although I have successfully displayed the route, I encountered an issue where both the origin and destination have identical ...

No pathways can be established within Core UI Angular

I've been attempting to use the router link attribute to redirect to a new page, but instead of landing on the expected page, I keep getting redirected to the dashboard. Below is an overview of how my project's structure looks: [![enter image de ...

Tips for switching between two icons within the same div by clicking on the icon

I am looking to implement a feature in angular2 that is similar to marking an email as Starred. For example, when I click on the empty star icon, it will make some service calls to check if the item should be starred. If the result is true, then a new icon ...

Authentication using SPA RSA 2048 encryption technology

For my current project involving Angular SPA development, the customer has requested the use of RSA 2048 for authentication. I'm uncertain about how the authentication token will be generated. My understanding is that the token should be created on th ...

Is it necessary to conceal Angular navigation controls when the user is not authenticated?

In Angular, is there a standardized method for hiding controls when the user is not logged in? We already have the CanActivate guard which checks if a user can access a route. Would it be better to hide the route initially if the user is not logged in or l ...

"Implementing a feature in Angular to automatically include a blank mat-option in all non-required mat-select elements

Is there a way to dynamically add an empty mat-option to all not required mat-select elements in my application? For example: <mat-form-field appearance="outline"> <mat-label>HMO</mat-label> <mat-select> ...

Creating a new formGroup and submitting it with model-driven form in Angular 2

Adding New Entries to FormArray Using input Field If I want to add values to an existing array through a form input, I can utilize the (click)="addAddress()" in the HTML file and define addAddress in the component.ts to update the values in an array withi ...

Ways to employ data binding for extracting a user-input value and performing multiplication operations with the enclosed {{ ...}} tags

My API response includes the price of a product, which is represented as {{price}} I have a system where I can add or reduce the number of products: <div class="number-input"> <h2>Price: {{price }}</h2> <button oncli ...

Swap references between two components at the same level

There are two instances of custom-component spawned by a shared parent with distinct data, each displayed as a tab in the mat-tab-group. <mat-tab-group> <mat-tab label="TAB1"> <ng-template matTabContent> <custom-componen ...

Passing a custom data type from a parent component to a child component in React

I'm currently working on developing a unique abstract table component that utilizes the MatTable component. This abstract table will serve as a child element, and my goal is to pass a custom interface (which functions like a type) from the parent to t ...

Ways to resolve the issue: ""@angular/fire"' does not contain the exported member 'AngularFireModule'.ts(2305) in an ionic, firebase, and

I am facing an issue while attempting to establish a connection between my app and a firebase database. The problem arises as I receive 4 error messages in the app.module.ts file: '"@angular/fire"' has no exported member 'AngularFi ...

FIXED-IONIC 3: The 'questions' property is missing from the 'Object' type

Encountering an issue with a single line of code and exhausted all resources in attempts to resolve it. Seeking assistance for my simple quiz, disregarding the current data presentation. The trouble arises within my data.ts file, specifically at one parti ...

Using TypeScript in the current class, transform a class member into a string

When converting a class member name to a string, I rely on the following function. However, in the example provided, we consistently need to specify the name of the Current Component. Is there a way to adjust the export function so that it always refers ...

Creating TypeScript object properties dynamically based on function arguments

One of my functions takes in a variable number of arguments and creates a new object with a unique hash for each argument. Can Typescript automatically determine the keys of the resulting object based on the function's arguments? For instance, I ha ...

Exploring the process of associating a string with a specific enum value in TypeScript

One scenario is if you receive a string value from the server and have an enum type with string values defined. In TypeScript, how can you convert the string value to the enum type? export enum ToolType { ORA= 'orange', ST= 'stone' , ...