1

This seems like it should be straight-forward, but I can't see what I'm doing wrong. I have a form on which some components are optionally enabled based on a yes/no radio button. I'm attempting to set the disabled attribute based on the boolean behind that radio button. If I set [disabled] to the radio button every thing works (but is reversed from the desired behavior). If I set [disabled] to the negation of the boolean, it suddenly doesn't work. I wrote up a Plunker to illustrate: NegationConditionExample. Simply remove the '!' from the oResponded variable and it will work but be reversed from the desired behavior.

Here's the code:

//our root app component
import {Component, NgModule} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
import { FormsModule } from '@angular/forms';
import { CommonModule }   from '@angular/common';

@Component({
  selector: 'my-app',
  template: `
    <form (ngSubmit)="onSubmit()" #resolveForm="ngForm">
      <div class="form-group">
        <label> Did anyone respond? </label>
        <div class="radio">
           <label>
              <input type="radio"
                     name="responded"
                     [(ngModel)]="oResponded"
                     #responded="ngModel"
                     value=true> Yes someone responded
          </label>
        </div>
        <div class="radio">
          <label>
              <input type="radio"
                     name="responded"
                     [(ngModel)]="oResponded"
                     #responded="ngModel"
                     value=false> No
          </label>
        </div>
      </div>
      <div class="form-group">
        <label for="responseType">What type of response?</label>
        <select class="form-control" id="responseType"
                required
                [(ngModel)]="oResponseType" name="responseType"
                #responseType="ngModel"
                [disabled]="!oResponded">
          <option *ngFor="let i of oResponseTypes" [value]="i">{{i}</option>
        </select>
        <div [hidden]="responseType.valid || responseType.pristine" class="alert alert-danger">
          Response Type is Required
        </div>
      </div>
      oResponded: {{oResponded}}
    </form>
  `,
})
export class App {
  oResponded: boolean;
  oResponseType: string;
  oResponseTypes: string[] = ["Agreed", "Disagreed", "Other"];
  constructor() {
    this.oResponded = false;
  }
}

@NgModule({
  imports: [ BrowserModule, FormsModule, CommonModule ],
  declarations: [ App ],
  bootstrap: [ App ]
})
export class AppModule {}`
Mutmansky
  • 577
  • 6
  • 16
  • Plunkr works as expected. I'm not sure you're aware, but the model is pulling the raw input value from whatever is assigned. This means that if the "No" radio button is clicked, the oResponded is true. From this, the negated oResponded is then false, meaning the select will be enabled. What is missing is the reverse as you've attached two radio buttons to the same model, making the oResponded value true every time you change selection. – gelliott181 Oct 07 '16 at 19:34
  • @gelliot181, that's not correct. The oResponded was always being updated set as the Yes/No were being selected. However, as folks below noted, I was not handling the value as a boolean, but rather as a string. So as soon as any radio button was selected, oResponded became a a string and any valid string would make oResponded evaluate to true and hence !oResponded evaluate to false. – Mutmansky Oct 07 '16 at 19:49

2 Answers2

2

It's because changing the radio button is actually setting the value of oResponded to a string type, not a boolean. I added === false: {{oResponded === "false"}} below your oResponded: {{oResponded}}, where you can see that initially, oResponded is a boolean value (set in the constructor) but switching the radio buttons switches it to a string value.

I suppose you could handle this by evaluating the string value instead, or make a method to convert the string value of the radio buttons to a boolean.

Dave V
  • 1,966
  • 9
  • 18
  • Indeed that's what I was missing. It was handling it as a string type. I updated the plunker with a print out of the result of the negation and came to the same conclusion. – Mutmansky Oct 07 '16 at 19:49
  • 1
    Günter's method is definitely the better way to handle it, I wasn't aware that making the value an angular parseable value would make it a true boolean, do it his way LOL – Dave V Oct 07 '16 at 19:51
2

I had to make 2 changes

  • add [] around value to get boolean values instead of strings
          <input type="radio"
                 name="responded"
                 [(ngModel)]="oResponded"
                 #responded="ngModel"
                 [value]="true"> Yes someone responded
  • set the disabled attribute as attribute instead of boolean and set it to null in case of false:
    <select class="form-control" id="responseType"
            required
            [(ngModel)]="oResponseType" name="responseType"
            #responseType="ngModel"
            [attr.disabled]="oResponded ? null : true">

Plunker example

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567