1

I'm working on a form on a dialog, from which one of the form fields uses mat-autocomplete. Submitted forms are added to a table. When the user clicks on a row of the table, the form dialog opens again and he or she can edit this previously submitted form.

Current behaviour: when user opens the form, the autocomplete field is already filled with the previously submitted value, and the autocomplete panel is open

Wanted behaviour: same thing but with autocomplete panel closed.

What I'm trying to do: @ViewChild(MatAutocompleteTrigger) autoComplete: MatAutocompleteTrigger; and then this.autoComplete.closePanel();

I've tried with #autoComplete or #MatAutocompleteTrigger selectors on input in HTML template.

The actual error I get is ERROR TypeError: Cannot read properties of undefined (reading 'closePanel'), because autocomplete is undefined.

I've also tried this approach: HTML:

<input #autoCompleteInput type="text" [matAutocomplete]="auto"/>

TS:

@ViewChild('autoCompleteInput', { read: MatAutocompleteTrigger }) 
autoComplete: MatAutocompleteTrigger;

I've seen a few questions about it: here, here, here, but can't make it work.

Code below:

HTML (showing only the autocomplete section)

    <mat-form-field class="top-form-field" appearance="outline">
      <mat-label>Brigada</mat-label>
      <input matInput
             #autoComplete
             aria-label="Brigada"
             [matAutocomplete]="auto"
             formControlName="nome_brigada">
      <mat-autocomplete #auto="matAutocomplete">
        <mat-option *ngFor="let brigade of filteredBrigades | async" [value]="brigade.name">
          <img class="option-img" aria-hidden [src]="brigade.typeIcon" height="25">
          <span>{{brigade.name}}</span> |
          <small>{{brigade.category}}</small>
          <span *ngIf="brigade.plate">
            | <small>{{brigade.plate}}</small>
          </span>
        </mat-option>
      </mat-autocomplete>
    </mat-form-field>

TS: (without imports)

OBS: when "row" is not null, it's the case when the user has clicked in the table and will edit the previously submitted form (the case I want the close the panel)

export interface Brigade {
  type: string;
  typeIcon: string;
  name: string;
  category: string;
  filterString: string;
  id_brigada: string;
  plate: string;
}

@Component({
  selector: 'select-brigade-dialog',
  templateUrl: 'select-brigade-dialog.html',
})
export class SelectBrigadeDialog {

  @ViewChild(MatAutocompleteTrigger) autoComplete: MatAutocompleteTrigger;

  public brigadeForm: FormGroup;
  brigadeCtrl = new FormControl('', [Validators.required]);
  filteredBrigades: Observable<Brigade[]>;

  public brigades: Brigade[] = [];

  public tipos_brigada:string[];
  public categorias_brigada:string[];
  public nomes_brigada: string[];

  combateChecked: boolean;
  rescaldoChecked: boolean;
  
  constructor(
    @Inject(MAT_DIALOG_DATA)
    public data: any,
    public fb: FormBuilder,
    private dtValidators: DatetimeValidators,
    private amplitude: AmplitudeService
  ) {

    this.combateChecked = false;
    this.rescaldoChecked = false;

    for (let b of data.brigadas){
      this.brigades.push({
        type: b['tipo_brigada'],
        typeIcon: brigadeIconMap[b['id_tipo_brigada']],
        name: b['nome_brigada'],
        category: b['categoria_brigada'],
        filterString: b['nome_brigada'] + b['placa'] + b['categoria_brigada'],
        id_brigada: b['id_brigada'],
        plate: b['placa']
      })
    }

    this.brigades.sort((a, b) => a.name.localeCompare(b.name));

    if (data.row === null){
      this.filterBrigades('');
    } else {
      this.filterBrigades(data.row['nome_brigada']);
    }

    let id_acionamento = `${data.id_report}_${data.len_acionamentos}`

    this.initForm(data.row, id_acionamento);
  }

  filterBrigades(nome_brigada) {
    this.filteredBrigades = this.brigadeCtrl.valueChanges.pipe(
      startWith(nome_brigada),
      map(brigade => (brigade ? this._filterBrigades(brigade) : this.brigades.slice())),
      );
    }
    
  private _filterBrigades(value: string): Brigade[] {
    const filterValue = value.toLowerCase();
    return this.brigades.filter(brigade => brigade.filterString.toLowerCase().includes(filterValue)).sort((a, b) => a.name.localeCompare(b.name));
  }
  
  initForm(row, id_acionamento){
    let datetime_now = formatDate(new Date(), 'yyyy-MM-ddTHH:mm', 'en-US');
    let dt_midnight = this.setMidnight();

    let dt_validators = [
      this.dtValidators.dtAcionamento(),
      this.dtValidators.dtCombate(),
      this.dtValidators.dtRescaldo(),
      this.dtValidators.dtChegadaCombate(),
      this.dtValidators.dtChegadaRescaldo(),
      this.dtValidators.dtFuturo(dt_midnight)
    ]
    
    if (row === null){
      this.brigadeForm = this.fb.group({
        nome_brigada: this.brigadeCtrl,
        contagem_equipe:['1',[Validators.required, Validators.min(1)]],
        dt_acionamento:[`${datetime_now}`,[Validators.required]],
        dt_chegada:[''],
        combate: false,
        dt_inicio_combate:[''],
        dt_fim_combate:[''],
        rescaldo: false,
        dt_inicio_rescaldo:[''],
        dt_fim_rescaldo:[''],
        id_acionamento:[id_acionamento],
        id_brigada: ['']
      },{
        validators: dt_validators,
      });
    } else {
      if (row['dt_inicio_combate'] !== null && row['dt_inicio_combate'] !== ''){
        this.combateChecked = true;
      };
      if (row['dt_inicio_rescaldo'] !== null && row['dt_inicio_rescaldo'] !== ''){
        this.rescaldoChecked = true;
      };
      this.brigadeForm = this.fb.group({
        nome_brigada: [row['nome_brigada'],[Validators.required]],
        contagem_equipe:[row['contagem_equipe'],[Validators.required, Validators.min(1)]],
        dt_acionamento:[row['dt_acionamento'],[Validators.required]],
        dt_chegada:[row['dt_chegada']],
        combate: this.combateChecked,
        dt_inicio_combate:[row['dt_inicio_combate']],
        dt_fim_combate:[row['dt_fim_combate']],
        rescaldo: this.rescaldoChecked,
        dt_inicio_rescaldo: [row['dt_inicio_rescaldo']],
        dt_fim_rescaldo: [row['dt_fim_rescaldo']],
        id_acionamento: [row['id_acionamento']],
        id_brigada: [row['id_brigada']]
      },{
        validators: dt_validators,
      });
      console.log('autocomplete: ', this.autoComplete)
      this.autoComplete.closePanel();
    }
  }
  • "when user opens the form, the autocomplete field is already filled with the previously submitted value, and the autocomplete panel is open" You mean to say like when user click on auto complete then panel not requires to open? – Parth M. Dave Nov 17 '22 at 13:29
  • As the autocomplete is the first form field, actually when the form dialog opens, the focus goes to the autocomplete, with no click/action from the user. Regardless of the form focus, I'd like the form to initialize withe the panel closed – Ludovic Beghin Nov 17 '22 at 13:33

1 Answers1

2
let dialogRef = this.dialog.open(DialogOverviewExampleDialog, {
  width: '250px',
  data: { name: this.name, animal: this.animal },
  autoFocus: false   <============================== this line
});

Maybe if I am not wrong then you have a problem with auto focus to first control. So, using above you can handle your task. If you still have no luck let me know. Happy coding.

Andre Silva
  • 4,782
  • 9
  • 52
  • 65
Parth M. Dave
  • 853
  • 1
  • 5
  • 16