12

Context

I'm writing a custom Angular component for a checkbox. The component renders a checkbox tag along with a label tag. The "id" attribute of the checkbox and the "for" attribute of the label are both set to the component's id property (an @Input to the component) to ensure that clicking the label will toggle the checkbox. A simplified version of the template looks like:

<div class="checkbox">
    <input type="checkbox" [id]="id" />
    <label [for]="id"><ng-content></ng-content></label>
</div>

Problem

When I set an "id" prop on my component (e.g. <my-checkbox id="hello">Check me</my-checkbox>), an "id" attribute is automatically set on the component wrapper tag in the DOM. This results in duplicate ids in the DOM because I'm already setting an "id" attribute on the checkbox inside the component. This is invalid and breaks the browser's default toggle-by-clicking-the-label behavior. The DOM output is:

<my-checkbox id=“my-checkbox” ng-reflect-id=“my-checkbox” ng-reflect-checked="true">
    <div ng-reflect-ng-class="[object Object]" class="checkbox">
        <input class="checkbox__element" type="checkbox" name="fire_missiles" ng-reflect-id=“my-checkbox” id=“my-checkbox” value=“fire_missiles” ng-reflect-checked="true">
        <label class="checkbox__label" ng-reflect-html-for=“my-checkbox” for=“my-checkbox”>
            Fire missiles?
        </label>
    </div>
</my-checkbox>

Is there a way to either a) get rid of the garbage container tag or b) stop the automatic reflection of the "id" prop onto the container as an attribute?

NOTE: Using an attribute selector applied to something like a div doesn't help, it just moves the extra "id" from <my-checkbox /> to the div.

TylerH
  • 20,799
  • 66
  • 75
  • 101
Elliot
  • 1,463
  • 1
  • 14
  • 14
  • Why don't you just change the `id` of the checkbox a bit, e.g. `` and ` – balu Sep 20 '17 at 12:20
  • I faced this issue and solved by taking an [id] as an timestamp. but my issue is, I have 4 checkbox on my form ( which I am copying multiple times) and to get unique id to all 4 of them, I need to create 4 seperate variable in my ts file like uniqueId1, uniqueId2..... – Akash Aug 05 '18 at 00:48

4 Answers4

9

I would simply rename the checkbox's id (and hence the label's for attribute) so that it doesn't clash with the component's id, like so:

<input id="{{ id }}-checkbox" …>
<label for="{{ id }}-checkbox">…</label>
Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
balu
  • 3,500
  • 4
  • 34
  • 35
5

You can pass id as expression:

<my-checkbox [id]="'hello'">Check me</my-checkbox>

In this case component tag does not contain id attribute in DOM, it contains only attribute ng-reflect-id, which does not affect default behavior for label.

Yuri Beliakov
  • 623
  • 7
  • 23
0

This is more of a hack, on your component you can do this:

constructor(elementRef: ElementRef) {
    elementRef.nativeElement.removeAttribute("id");
}

And that should get rid of your id on your <my-checkbox></my-checkbox>

penleychan
  • 5,370
  • 1
  • 17
  • 28
0

I was having a similar issue. I added # sign before ID and use the ngModel to bind the property

<input id="#{{ id }}-checkbox" …>
<label for="#{{ id }}-checkbox">…</label>
David Buck
  • 3,752
  • 35
  • 31
  • 35
Mi10_Shah
  • 21
  • 3