Changing the color of a specific span using Angular

I am working with a dynamic mat-table where columns are added and populated on the fly. The table headers are styled using divs and spans. My goal is to change the color of a header to black when clicked, but also un-toggle any previously selected header.

At the moment, I have managed to toggle a header's color, but I am struggling with untoggling another header. Initially, all the spans were being toggled at once, but I was able to fix this by toggling based on each span's ID.

Below is a snippet of the HTML code I have implemented:

<table mat-table [dataSource]="dataSource">
      <ng-container matColumnDef="{{column.columnName1}}" *ngFor = "let column of displayColumns">
          <th mat-header-cell *matHeaderCellDef>
            <div *ngIf = "column.stackedHeader">
              <div [ngStyle] = "{'color': (column.toggled) ? 'black' : 'grey'}" (click) = "toggleColumn($event)" class = "column-header" id = "{{column.columnName1}}">
                {{ column.columnHeader1 }}
              </div>
              <div (click) = "toggleColumn($event)" class = "column-header" id = "{{column.columnName2}}">
                {{ column.columnHeader2 }}
              </div>
            </div>
            <div *ngIf = "!column.stackedHeader" (click) = "toggleLocationColumn($event)" class = "column-header" id = "{{column.columnName1}}">
              {{column.columnHeader1}}
            </div>
          </th>
toggleColumn($event) {
    const columnId = $event.toElement.id;
    this.columnToggled.emit($event);
    for (let i = 0; i <= this.displayColumns.length; i++) {
      if (columnId === this.displayColumns[i].columnName1) {
        this.displayColumns[i].toggled = !this.displayColumns[i].toggled;
      }
    }
  }

Here is an example array that I use to populate the table:


[{
    columnName1: 'Pickup',
    columnHeader1: 'Pickup',
    columnName2: 'Delivery',
    columnHeader2: 'Delivery',
    stackedHeader: true,
    stackedRow: true,
    toggled: false
  },
  {
    columnName1: 'FromCity',
    columnHeader1: 'From',
    columnName2: 'ToCity',
    columnHeader2: 'To',
    stackedHeader: true,
    stackedRow: true,
    toggled: false
  }]

Answer №1

The complete picture may be a bit blurry, with some parts missing, but I have some suggestions for refactoring the code to reduce errors.

Instead of passing the $event when defining click handlers in the template, you can pass any variable defined within the template itself.

<table mat-table [dataSource]="dataSource">
    <ng-container matColumnDef="{{column.columnName1}}" *ngFor = "let column of displayColumns">
        <!-- ... -->
            <!-- take note of the toggleColumn call below and the missing 'id' attribute -->
            <div ... (click) = "toggleColumn(column)" class = "column-header" >
        <!-- ... -->

This way, instead of receiving the DOM element, you receive the actual business object. This allows for the use of types and eliminates the need for an id on the clicked DOM element as well. The current implementation of toggleColumn seems a bit complex. Using a for-i loop can introduce errors, so it's better to use forEach which also enhances code readability due to fewer array references. Here's how I rewrote the method:

toggleColumn(selectedColumn: Column) {
    this.columnToggled.emit($event);
    this.displayColumns.forEach((otherColumn: Column) => {
        otherColumn.toggled = otherColumn.id === selectedColumn.id;
    });
  }

Upon further reflection, it appears that the issue might be that only the selected column's toggled field is being updated, while others remain unaffected. Check out the criteria within the if statement:

for (let i = 0; i <= this.displayColumns.length; i++) {
    if (columnId === this.displayColumns[i].columnName1) {
        this.displayColumns[i].toggled = !this.displayColumns[i].toggled;
    }
}

A simple solution could be to remove the if condition from the above statement and simply toggle the toggled state for all columns.

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

What is the best way to pass a value back to the main function from an async.eachOfSeries function?

Currently, I am utilizing the async npm library in my project. I am interested in finding a way to return the value of 'someVar' back to the main function. The documentation indicates that it returns a promise if a callback is not provided. Howe ...

Enable Cursor Display in Readonly Input Fields

Consider this scenario: Setting an input field to .readOnly = true replaces the text cursor with a pointer arrow cursor, preventing users from entering or modifying the field. Interestingly, clicking into a readonly input field that already contains text s ...

What steps can I take to ensure that the v-main element occupies at least 70% of the viewport height in Vuetify?

As a newcomer to Vuetify, I am still learning the ropes. One thing I've noticed is that <v-main> automatically expands to fill the space between <v-app-bar> and <v-footer>, taking up the entire viewport height. My concern arises wh ...

What could be the reason for box-shadows not appearing properly on Safari browsers?

Why are box shadows with decimals sometimes not displayed in Safari? Is there a solution to this issue? Here's an example of the code: div { width: 200px; height: 200px; box-shadow: 0px 0.0351725rem 0.0351725rem 0px, 0px 0px 0px 0.0175862re ...

Transferring session data through AJAX in PHP

I'm currently developing an app using PhoneGap. However, PhoneGap only supports HTML, CSS, and JS, not PHP. This led me to the workaround of placing the PHP file on a remote server and using AJAX to call it via the server's URL. My issue now is ...

Ensure that the input box expands to occupy the entire HTML page

After reviewing numerous pages and questions related to this topic, I have located the correct solution but am struggling to implement it. My goal is to achieve a similar outcome to the second question, but I'm having difficulty figuring out how to do ...

Ways to modify the pre-defined value in a TextField

I encountered a situation where I have a form with pre-filled data from a specific country. The data is initially read-only, but the user can click on the edit button if they wish to make changes. The issue arises when trying to edit the value in the Text ...

Encountering a TypeScript React issue with passing objects to context in code

Within my project, there is a context provider that acts as an object containing various properties: <Provider value={ { scaleNum: scaleNum, // number scaleLet: scaleLet, // string ...

Shifting Elements - Navigation triggers subtle movements in CSS styles as you move across pages

I've noticed a strange issue on my website where certain elements seem to be shifting slightly when navigating between different pages. Here's a quick video clip demonstrating the problem. It appears that these elements are not staying static as ...

Mastering the art of scrolling and selecting items concurrently using the mouse in Vue

Struggling with a fascinating challenge of scrolling while selecting items using mouse drag in both up and down directions. Here's a screenshot for reference: https://i.stack.imgur.com/giMwY.png Check out my code: https://codesandbox.io/s/select-i ...

Styles are not applied by Tailwind to components in the pages folder

NextJS project was already created with tailwind support, so I didn't have to set it up myself. However, when I add className to an HTML element in a component within the pages/ folder, it simply doesn't work, even though the Elements panel in D ...

Error message thrown by node express.js indicating that response headers cannot be reset once they have been sent

As a newcomer to both node and express, I may be making a silly mistake. If you want to see the complete source code, please visit: https://github.com/wa1gon/aclogGate/tree/master/server logRouter.get("/loggate/v1/listall", function(req, res) { let ...

One the year is chosen, it will be automatically hidden and no longer available for selection

<div ng-repeat="localcost in vm.project.localCosts" layout="column"> <md-select name="localcost_{{$index}}"ng-model="localcost.year" flex> <md-option ng-repeat="years in vm.getYears()" ng-value="years">{{years}}< ...

Tips for effective page management

After creating a navbar in my project, I've come to the realization that it requires a component for each page and subpage. This seems redundant especially when dealing with multiple navigation options like shown in this image. Is it necessary to crea ...

When encountering an OR operator, Javascript will cease execution of the remaining conditions

This is a basic JavaScript form-validation I created. All the document.form.*.value references are present on my page, except for the document.form.dasdasdas.value ==''. In the code below, the purpose is to display an error if any of the forms a ...

Choose the initial unordered list within a specific division through Jquery

In a div, there is a ul. Inside a li, there is another ul. The task is to select only the first ul inside the div using jQuery. The HTML markup: <div class="parent"> <div class="clearfix"> <div class="another-div"> <ul cl ...

I'm trying to find a way to access a particular field within an HTML document using JavaScript in Node.js. Can anyone

<Response> <SMSMessageData> <Message>Delivered to 1/1 Total Cost: NGN 2.2000</Message> <Recipients> <Recipient> <number>+9109199282928</number> <cost>NGN 2.2000&l ...

Test the file upload functionality of a Node Js application by simulating the process using Chai

My API testing involves receiving a file as input. I have successfully used the attach() function for this purpose. To cover all scenarios, I anticipate using around 20 different input files. Rather than storing these 20 files individually, my idea is to c ...

Tips for Incorporating the YouTube Iframe API into Your ReactJS Project

While working in React, I am attempting to build a custom YouTube player component that includes a new set of player controls. The YouTube iframe API provides the following code snippet for creating a player instance: var tag = document.createElement(&ap ...

Tips for Accessing a New Website Using the Floating Layer Close Button

How can I trigger the opening of a new browser window when a visitor clicks the close "x" on my floating layer ad? The close button is within an HTML link code ("a href"), but simply putting a URL in there does not seem to work. <script language=" ...