Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 Material - Using MD's autocomplete example in a form

Is there a way to have the autocomplete work inside a form? I have a form that takes input for an address. I'm using autocomplete (copied from Material Design's docs) for states (this is in the US) and that is working except that the selected state is not being set to user.state. So when I console log out the myForm.form.value on submit it looks like this:

user.name : "Test"
user.phone: ...
etc.

with user.state not even showing up.

My (relevant) code:

<md-input-container>
  <input 
    mdInput 
    placeholder="State" 
    [mdAutocomplete]="auto"
    [formControl]="stateCtrl"
    name="user.state" 
    [(ngModel)]="user.state"
  >
</md-input-container>

<md-autocomplete 
    #auto="mdAutocomplete"
>
  <md-option 
    *ngFor="let state of filteredStates | async" [value]="state"
    (onSelectionChange)="selectState(state)"
  >
    {{ state }}
  </md-option>
</md-autocomplete> 

TS:

  constructor(public dialog: MdDialog,) { 
    this.stateCtrl = new FormControl();
    this.filteredStates = this.stateCtrl.valueChanges
        .startWith(null)
        .map(name => this.filterStates(name));
  }

  filterStates(val: string) {
    return val ? this.states.filter(s => new RegExp(`^${val}`, 'gi').test(s))
               : this.states;
  }

Even when I try to use (onSelectionChange) to call function selectState(state) to set the user.state it still doesn't show up when I console.log the form on submit.

  selectState(value){
    this.user.state = value;
  }
like image 511
av0000 Avatar asked Jun 16 '17 20:06

av0000


2 Answers

Take a look at this GitHub example: Demo with md-autocomplete (forms)

There is an example with both reactive and template-driven form. With the template driven form you remove the formControl completely, and just use [(ngModel)] and (ngModelChange) instead. Here's sample for you with the template-driven solution:

<form #f="ngForm">
  <md-input-container>
    <input mdInput placeholder="State" [mdAutocomplete]="tdAuto" name="state" 
       #state="ngModel" [(ngModel)]="currentState"
      (ngModelChange)="tdStates = filterStates(currentState)">
  </md-input-container>

  <md-autocomplete #tdAuto="mdAutocomplete">
    <md-option *ngFor="let state of tdStates" [value]="state">
      <span>{{ state }}</span>
    </md-option>
  </md-autocomplete>    
</form>

and in component we assign the filtered value to a different variable (tdStates) and keep all states in the states array:

filterStates(val: string) {
  if (val) {
    const filterValue = val.toLowerCase();
    return this.states.filter(state => state.toLowerCase().startsWith(filterValue));
  }
  return this.states;
}

DEMO

like image 105
AT82 Avatar answered Mar 05 '23 22:03

AT82


I have taken the example form from material's website and added md-autocomplete to it. In the demo, you can filter and select a state from the autocomplete. When the form is submitted, you can see the value getting passed to alert.

HTML:

Full code in plunker demo

<form>

// add all form code

<md-autocomplete #auto="mdAutocomplete" >
    <md-option *ngFor="let state of filteredStates | async" [value]="state" (onSelectionChange)="selectState(state, addForm.value)">
      {{ state }}
    </md-option>
</md-autocomplete>

</form>

app.ts:

selectState(state, form){
    form.state = state;
  }
like image 35
Nehal Avatar answered Mar 05 '23 22:03

Nehal