The style of an Angular directive becomes lost when it is bound to a value within the ngFor

In a dynamic scenario of passing values within an ngFor loop, my directive seems to lose its styling.

This particular directive is designed for a datatable column where the column name is specified.

@Directive({ selector: '[my-dt-column]' })
export class MyDTColumn{
    @Output() onSort: EventEmitter<any> = new EventEmitter();

    @HostBinding('class.sorted-asc') sortedAsc;
    @HostBinding('class.sorted-desc') sortedDesc;
    _sortOrder: string;
    public sort(order?: string){
        this._sortOrder = order !== undefined ? order : (!this._sortOrder || this._sortOrder == 'desc') ?'asc' : 'desc'
        this.sortedAsc = this.sortOrder === 'asc';
        this.sortedDesc = this.sortOrder === 'desc';
    }
    get sortOrder(): string{
        return this._sortOrder;
    }
    get isSorted(): boolean{
        return this._sortOrder !== undefined && this._sortOrder !== null && this._sortOrder !== '';
    }
    column: string;

    @Input('my-dt-column')
    set setItem(column: any){
        this.column = column;

    }

    @HostListener('click') onClick(){
        this.sort();
        this.onSort.emit({orderBy:this.column, sortOrder:this._sortOrder});
    }

    constructor(private el: ElementRef){}
}

Furthermore, some specific styles are applied to it, mainly indicating the sorting direction with an arrow-icon and managing its order.

:host >>>> table [my-dt-column]{
    cursor: pointer;
}
:host >>>> table  [my-dt-column] md-icon{
    font-size: 10px;
    height: 16px;
    line-height: 16px;
    vertical-align: middle;
    opacity: 0;
    color: rgba(0, 0, 0, 0.38);
    transition: transform .25s, opacity .25s;
    transform-origin: center center;
    text-align: center;
}
:host >>>> table [my-dt-column].sorted-asc,
:host >>>> table [my-dt-column].sorted-desc{
    color: rgba(0, 0, 0, 0.87);
}
:host >>>> table [my-dt-column].sorted-asc md-icon,
:host >>>> table [my-dt-column].sorted-desc md-icon{
    opacity: 1;
    color: rgba(0, 0, 0, 0.87);
}
:host >>>> table [my-dt-column].sorted-asc md-icon{
    transform: rotate(0deg);
}
:host >>>> table [my-dt-column].sorted-desc md-icon{
    transform: rotate(180deg);
}
:host >>>> table [my-dt-column]:hover md-icon{
    opacity: 1;
}

Initially, I manually inserted table headers using this directive in HTML as shown below:

<th my-dt-column="ColumnName">some code</th>
<th my-dt-column="Column2Name">some code</th>
<th my-dt-column="Column3Name">some code</th>
<th my-dt-column="Column4Name">some code</th>

To avoid typing mistakes, I attempted a dynamically generated approach by creating an array in the parent component with the names of columns added through ngFor in HTML.

The issue arises where the style fails to apply despite setting the column name correctly.

<ng-container *ngFor="let column of columns">
   <th [my-dt-column]="column.name">some code</th>
</ng-container>

Strangely, when a random string is bound instead, the style functions properly but results in incorrect column names.

<ng-container *ngFor="let column of columns">
   <th my-dt-column="randomstring">some code</th>
</ng-container>

I've searched for solutions without success. Any insights or assistance would be greatly appreciated.

EDIT: One more observation - binding a random string shows up correctly in HTML attributes, whereas using the dynamically generated column name from ngFor does not display in the HTML despite being provided.

<th _ngcontent-c11="" mdtooltipposition="right" my-dt-column="randomstring" ng-reflect-position="right" ng-reflect-message="" ng-reflect-set-item="randomstring" class="">some code</th>
<th _ngcontent-c11="" mdtooltipposition="right" ng-reflect-position="right" ng-reflect-message="" ng-reflect-set-item="InstrumentTypeName" class="">some code</th>

Answer №1

When looking to preserve the attribute, you can utilize @HostBinding in Angular:

import { HostBinding } from '@angular/core';

....
column: string;
@HostBinding('attr.my-dt-column') @Input('my-dt-column')
set setItem(column: any){
    this.column = column;
}
get setItem() {
  return this.column
}

It is important to note that a getter must also be declared.

View Plunker Example

Alternatively, you can use the host property in your component:

host: {
  '[attr.my-dt-column]': 'column'
}

Check Out This Plunker Demo

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

Angular 2 property accessor designed similar to Linq style

Many times, we come across an array (IEnumerable) property where we need to extract specific values. In C#, we can achieve this by using the following code snippet: public AssetModel PromoImage { get { return Assets.FirstOrDefa ...

Configuring Jupyter notebooks to be shared across multiple servers

Working in an environment with multiple servers, I want to streamline my .jupyter configuration across all servers without the hassle of manual synchronization. Fortunately, this can be easily accomplished by setting the JUPYTER_CONFIG_DIR environment vari ...

Exploring alternative options to replace PEAR's HTML_Table

I am encountering difficulties while using PEAR HTML_Table (strict error, bug still unresolved). I am seeking a standardized method to generate HTML output that creates a table from associative arrays. The key should be in col#1 and the value in col#2. If ...

I am experiencing an issue where the Javascript keydown event does not recognize the character "@" in the EDGE browser

Currently, I am developing a mentioning directive that displays a list of users when the user types in an input field (a div with contentEditable=true). The user can then insert the name of the desired user in a specific format. The list is supposed to be ...

Tips for showcasing mobile view content on a full web screen

Link to the Reference Page:- https://i.sstatic.net/fmahp.png This query has been raised by a developer before, but the provided solution did not work for me. Link to the original question:- How to Change Desktop View, Tablet View, and Mobile View Inside ...

Mapping URLs to objects in JavaScript, TypeScript, and Angular4

I have implemented a class called SearchFilter class SearchFilter { constructor(bucket: string, pin: number, qty: number, category: string) { } } When the user performs a search, I populate the filter i ...

"Trouble with jQuery: Selecting an image to change isn't

Can someone help me figure out why my simple image change on a dropdown isn't working correctly? You can find the code on this Jsfiddle. Thank you for any assistance! $("#display_avatar").change(function(){ $("img[name=preview]").attr("src", $( ...

Trouble aligning Bootstrap 4 form fields in a horizontal layout

I'm struggling to align the user image and biography form fields with the rest of my signup form in Bootstrap 4. I've tried tweaking the CSS in various ways, but I can't achieve the desired visual effect: I want the biography and photo upl ...

How to automatically select the first item in a populated dropdown list using Vue JS

My HTML select element is populated with options from a server, but when using v-model, it initially selects an empty option instead of the first one. I came across a solution on a post which suggests selecting the first option manually, but since the dat ...

SVG images suddenly disappearing in Chrome following a javascript script execution

My webpage has a sticky footer, but I am experiencing issues with SVG files not displaying in Chrome when the javascript for color changing on hover is enabled. Interestingly, disabling the javascript allows the images to load properly in Chrome. I have t ...

Avoiding using the symbols < and > in JavaScript code before assigning it to InnerHtml

I am dynamically adding JavaScript code to a script tag by setting the InnerHtml property of the HtmlNode. scriptNode.InnerHtml = new_script; The issue arises when my JavaScript code contains less than < and/or greater than > characters, which dist ...

The problem with floating labels

I have been attempting to incorporate the floatlabels feature from floatlabels, but I am encountering difficulties in getting it to work properly. Here is the sequence of steps I have taken: Firstly, I include the JS file <script src="js/floatlabels. ...

What is the best way to update or change a value in a JSON file?

This specific file is structured in JSON format shown below: { "ClusterName": { "Description": "Name of the dbX Cluster", "Type": "String", "MinLength": "1", "MaxLength": "64", "AllowedPattern": "[-_ a-zA-Z0-9]* ...

Managing Variants in SCSS with BEM Approach: A Comprehensive Guide

Trying to solve a frustrating issue with BEM can be quite the challenge. I currently use the BEM methodology for developing UI elements in my application. For example: <div class="card"> <h2 class="card__title">S ...

Is it possible to achieve the lower link set in a pure CSS horizontal menu where the horizontal link set is positioned below horizontal text tabs?

I am attempting to design a pure CSS on-hover horizontal menu. I have made some progress on my design, as shown in http://jsfiddle.net/dq8z192L/11/ The goal is to have a menu that expands horizontally when hovered over. Each tab reveals a set of links be ...

Challenges I encountered with styling my navigation bar using CSS

My goal is to have the font color change to blue when a user hovers over a link in my navigation bar. I've tried using the following CSS code: #nav a:hover{ color: #1B8AD8; background: none; text-decoration: none; } However, it's not working as ...

How can I create a nested border graphic with round corners over text enclosed within <span></span> tags?

Can we create a visual representation of nested rounded rectangles to represent each <span></span> grouping? For instance, in HTML source code <span>She <span>loves</span> him a <span>lot</span>.</span> Th ...

The hierarchy of CSS cascading influence

Looking for some help with styling HTML: <div id="menubar"> <menu id="menubarTransportControls">Foobar</menu> </div> Curious why this CSS rule... #menubar menu { width: auto; } ...is overriding... #menubarTransportContr ...

Ways to eliminate the existing image during an image upload process

When a user decides to change their profile picture, I want the link in the database to be updated and the new image moved to the upload folder. The code should also remove the previous image associated with that specific user from the upload folder. The ...

Error Message: React does not allow objects as valid children

I'm currently working on developing a movie react application, inspired by similar platforms like Netflix. To enhance the user interface, I have incorporated Bootstrap into my project. One of the key features I have implemented is a login form that gr ...