ng-zorro-antd icon indicating copy to clipboard operation
ng-zorro-antd copied to clipboard

Support of passing custom html attributes in nz component like data-*, aria-*, role

Open blephy opened this issue 3 years ago • 1 comments

What problem does this feature solve?

In my compagny, we use data-test-id pattern to aim on HTMLElement in our unit and e2e tests.

Actually, we can not pass custom html attributes in nz components and this is painfull.

To achieve our goal, we can use a workaround like that :

<div data-test-id="mycontainer__mycard">
    <nz-card ...></nz-card>
</div>

But this is not ideal, as it adds a lot of useless HTMLElement in app, diminishing rendering performances.

However, i didn't try to use a directive that apply on his host an attribute passed in input. This could work, like this :

<nz-card myDirective [directiveId]="mycontainer__mycard"></nz-card>

If this could work, this is not optimal because this should increase the javascript execution time for nothing. Produce a raw template would be better.

What does the proposed API look like?

The goal of this feature is to permit to pass custom data attributes like data-*, aria-*, role this way :

<nz-card data-test-id="mycontainer__mycard"></nz-card>

<nz-button aria-label="my-label"></nz-button>

<nz-button role="my-role"></nz-button>

EDIT:

I have a POC working with a directive like i describe bellow.

import { Directive, ElementRef, Input, OnInit, Renderer2 } from "@angular/core";

/**
 * Add HTML attribute directive
 *
 * @description Add html attribute on hosted HTMLElement. Workaround until https://github.com/NG-ZORRO/ng-zorro-antd/issues/6725 resolution
 * @example <my-html-element addHtmlAttribute attributeName="data-test-id" attributeValue="my_test_id"></my-html-element>
 */
@Directive({
    selector: "[addHtmlAttribute]"
})
export class AddHTMLAttributeDirective implements OnInit {
    /**
     * Data name
     */
    @Input() attributeName = "data-test-id";
    /**
     * Data value
     */
    @Input() attributeValue;
    /**
     * Directive contructor
     *
     * @param el Html element
     * @param renderer Renderer angular function
     */
    constructor(private readonly el: ElementRef, private readonly renderer: Renderer2) {}
    /**
     * On directive initialization
     */
    ngOnInit(): void {
        if (this.attributeName && this.attributeValue && this.el.nativeElement) {
            this.addAttributeOnHostElement();
        }
    }
    /**
     * Add attribute on host element
     */
    addAttributeOnHostElement(): void {
        this.renderer.setAttribute(this.el.nativeElement, this.attributeName, this.attributeValue);
    }
}
<nz-card addHtmlAttribute attributeValue="my_data_test_id">

Even if it works, implementing this directive on each nz component that we would to pass custom HTML attribute will produce two render instead on one at the component initialization. If performances are a pre-required, this is really not ideal.

Is something can be done to achieve this ?

blephy avatar May 28 '21 14:05 blephy

Any updates on this?

danduh avatar Jan 23 '24 06:01 danduh