av0000
av0000

Reputation: 1967

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;
  }

Upvotes: 7

Views: 13396

Answers (4)

Mehmet Fethi
Mehmet Fethi

Reputation: 11

  states = [];
  tdStates = [];
  currentState = '';

  ngOnInit() {
    this.states= [
      {code: 'AL', name: 'Alabama'},
      {code: 'AK', name: 'Alaska'},
      {code: 'AZ', name: 'Arizona'},
      {code: 'AR', name: 'Arkansas'},
      {code: 'CA', name: 'California'},
      {code: 'CO', name: 'Colorado'},
      {code: 'CT', name: 'Connecticut'},
      {code: 'DE', name: 'Delaware'},
      {code: 'FL', name: 'Florida'},
      {code: 'GA', name: 'Georgia'},
      {code: 'HI', name: 'Hawaii'},
      {code: 'ID', name: 'Idaho'},
      {code: 'IL', name: 'Illinois'},
      {code: 'IN', name: 'Indiana'},
      {code: 'IA', name: 'Iowa'},
      {code: 'KS', name: 'Kansas'},
      {code: 'KY', name: 'Kentucky'},
      {code: 'LA', name: 'Louisiana'},
      {code: 'ME', name: 'Maine'},
      {code: 'MD', name: 'Maryland'},
      {code: 'MA', name: 'Massachusetts'},
      {code: 'MI', name: 'Michigan'},
      {code: 'MN', name: 'Minnesota'},
      {code: 'MS', name: 'Mississippi'},
      {code: 'MO', name: 'Missouri'},
      {code: 'MT', name: 'Montana'},
      {code: 'NE', name: 'Nebraska'},
      {code: 'NV', name: 'Nevada'},
      {code: 'NH', name: 'New Hampshire'},
      {code: 'NJ', name: 'New Jersey'},
      {code: 'NM', name: 'New Mexico'},
      {code: 'NY', name: 'New York'},
      {code: 'NC', name: 'North Carolina'},
      {code: 'ND', name: 'North Dakota'},
      {code: 'OH', name: 'Ohio'},
      {code: 'OK', name: 'Oklahoma'},
      {code: 'OR', name: 'Oregon'},
      {code: 'PA', name: 'Pennsylvania'},
      {code: 'RI', name: 'Rhode Island'},
      {code: 'SC', name: 'South Carolina'},
      {code: 'SD', name: 'South Dakota'},
      {code: 'TN', name: 'Tennessee'},
      {code: 'TX', name: 'Texas'},
      {code: 'UT', name: 'Utah'},
      {code: 'VT', name: 'Vermont'},
      {code: 'VA', name: 'Virginia'},
      {code: 'WA', name: 'Washington'},
      {code: 'WV', name: 'West Virginia'},
      {code: 'WI', name: 'Wisconsin'},
      {code: 'WY', name: 'Wyoming'},
    ];
  }

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

Upvotes: 1

Mehmet Fethi
Mehmet Fethi

Reputation: 11

  <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.name">
      <span>{{ state.name }}</span>
    </md-option>
  </md-autocomplete>

Upvotes: 0

AVJT82
AVJT82

Reputation: 73337

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

Upvotes: 16

Nehal
Nehal

Reputation: 13297

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;
  }

Upvotes: 2

Related Questions