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.

2
  • Why don't you just change the id of the checkbox a bit, e.g. <input id="{{ id }}-checkbox"> and <label for="{{ id }}-checkbox">? Commented Sep 20, 2017 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..... Commented Aug 5, 2018 at 0:48

4 Answers 4

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>
Sign up to request clarification or add additional context in comments.

Comments

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.

Comments

1

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>

Comments

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>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.