Search code examples
angularangular2-template

Angular 2 [disabled] only works on some controls


I've got a large form that is generated dynamically based on data I'm given from the server. To generate radio buttons, I use the following HTML:

<ng-container *ngSwitchCase="'RADIO'">
  <td *ngFor="let option of item.SelectOptions">
    <div class="input-group">
      <input type="radio"
        [(ngModel)]="item.PricingSelectIndex"
        name="{{ item.UIName }}RadioButton"
        id="{{ item.UIName }}{{ option.PricingSelectIndex }}"
        [value]="option.PricingSelectIndex"
        [disabled]="item.ReadonlyTF"
        (click)="saveField(item.UIName, 'SelectIndex', option.PricingSelectIndex)" />
      <label for="{{ item.UIName }}{{ option.PricingSelectIndex }}" style="margin-left: 5px;">
        {{ option.Label }}
        <i class="fa fa-question-circle" [tooltip]="item.TooltipText" placement="right" *ngIf="item.TooltipText"></i>
      </label>
    </div>
  </td>
</ng-container>

Obviously this is part of a larger page, which looks at each item from the data and generates the form based on the item's ControlType property-- this is the HTML for radio buttons. The data item includes a property called ReadonlyTF which tells me whether the control should be disabled (e.g. read-only). The item then includes a SelectOptions property which is an array of smaller items, each of which maps to one radio button in the set. (So for example, the control I'm having trouble with has two SelectOptions, one for Yes and one for No.) Each radio button is therefore generated with identical HTML.

Here's the weird thing. In the control in question, the first radio button generated is disabled (which is what I want), but the second one isn't.

yesnodisabled

If you look closely you can see that Yes is disabled but No is not! Here's how the two controls are rendered in Chrome's Elements tab:

elements

Both include ng-reflect-is-disabled="true" but only the first is actually disabled. The second button is missing ng-reflect-value. Again, these are being rendered with the exact same HTML snippet.

I'm using Angular 2.4.6, Typescript 2.1.5, bootstrap 3.3.7, and angular-cli to compile. There's no supporting TS in the component that would affect this: I get the data and pop it into a property that is then picked up by the HTML template, and that's it. I thought it might be some sort of change detection issue, but forcing it with changeDetectorRef.detectChanges() didn't do anything. I'm stumped on this but I can't have an active radio button sitting out there for anybody to click!

Thanks!


Solution

  • The reason this is occurring is because you have multiple input elements with NgModel directive and the same name attribute. The internal logic of NgModel toggles disable() and enable() on the form control based upon the value of the disabled input. Since you have only one form control due to the name conflict some where further down line only the first element gets updated.

    Make the name attributes unique and your problem should go away.

    You can walk through this behavior if you view the source for ng_model.ts.