Параметр Angular Material OptionSelected не срабатывает при значении в поле ввода - PullRequest
0 голосов
/ 01 мая 2019

Я использую чипы ввода углового материала с автозаполнением, у меня есть немного сложная настройка, где, если пользователь пытается выбрать вариант, который еще не существует, появляется диалоговое окно, и они могут создать новый параметр и для этого создан чип

Проблема в том, что пользователь вводит часть имени опции, например, «we» при поиске «western» перемещает мышь вниз и нажимает на «western», диалоговое окно по-прежнему всплывает изнутри matChipInputTokenEnd, даже если я считаю, что optionSelected должно быть запущено.

Когда я использую клавиши со стрелками, чтобы выбрать «западный» и нажимаю ввод вместо использования мыши, это работает как ожидалось. «западный» чип создан.

как сделать щелчок мышью по параметру из раскрывающегося списка, действовать так же, как стрелки, чтобы выделить параметр, и нажать клавишу ввода?

редактирование: проблема исчезла при удалении диалога изнутри add ()

edit 2: Я решил пока отказаться от этой функции, я потратил целую неделю, пробуя все, и это действительно позор, потому что я так близко, если был какой-то способ обнаружить, был ли matChipInputTokenEnd запущен через щелчок по сравнению с вводом, я мог бы решить это, если кто-нибудь найдет способ открыть диалог из add () или если есть более подходящий способ сделать это, пожалуйста, дайте мне знать. Единственная альтернатива, о которой я могу подумать, - это использовать базовую функцию add (), например, из exampeles, и добавить dialogData в массив, а затем onSubmit для родительской формы, всплывающей диалоговое окно, чтобы заполнить остальные детали элемента, но мне не нравится пользовательский опыт, так что я не уверен, что оно того стоит.

шаблон

   <mat-form-field class="full-width">
    <mat-chip-list #modifierChipList>
      <mat-chip
        *ngFor="let modifier of selectedModifiers"
        [selectable]="selectable"
        [removable]="removable"
        (removed)="remove(modifier,'selectedModifiers','modifierList')">
        {{modifier}}
        <mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
      </mat-chip>
      <input
        (click)="focusOut()"
        placeholder="Modifiers"
        #modifierInput
        [formControl]="modifierCtrl"
        [matAutocomplete]="autoModifier"
        [matChipInputFor]="modifierChipList"
        [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
        [matChipInputAddOnBlur]="addOnBlur"
        (matChipInputTokenEnd)="add($event, 'selectedModifiers', 'modifierList', 'modifierCtrl', 'modifier', filteredModifiers)">
    </mat-chip-list>
    <mat-autocomplete #autoModifier="matAutocomplete" (optionSelected)="selected($event, 'selectedModifiers', 'modifierInput', 'modifierCtrl', 'modifier')">
      <mat-option *ngFor="let modifier of filteredModifiers | async" [value]="modifier">
        {{modifier}}
      </mat-option>
    </mat-autocomplete>
  </mat-form-field>

ц

add(event: MatChipInputEvent, selectedItems, allItemsList, ctrl, type, filteredList): void { 

    const options = {};

      const input = event.input;
      const value = event.value;

      if(!this.autoModifier.isOpen || this[allItemsList].indexOf(value) < 0 ){


      // Add our new item to both the DB and local selected items
      if ((value || '').trim()) {

        if(!this[allItemsList].includes(value.trim())){

          switch(type){ 
            case 'category': 
              break;

            case 'option': 
              options['Type'] = this.typeList;
              options['Categories'] = this.categoryList;
              break;

            case 'component': 
              options['Options'] = this.optionList;
              options['Categories'] = this.categoryList;
              break;

            case 'modifier':
              options['Additions'] = this.optionList;
              options['Removals'] = this.optionList;
              options['Options'] = this.optionList;
              options['Categories'] = this.categoryList;
              options['Type'] = this.typeList;
              break;

            case 'tax':
              break;

            default:
              break;
          }

          let dialogQuestions = this.service.getQuestions(type, options);
          //open a modal to create that item
          const dialogRef = this.dialog.open(DialogComponent, {
            width: '70%',
            data: {
              dialog: this,
              type: type,
              details:{
                name:value,
                questions: dialogQuestions
              }
            },
          });


          dialogRef.afterClosed().subscribe(result => {
            this[allItemsList].push(result.name);
            this[selectedItems].push(result.name);
            this.autocomplete.closePanel();//this doesnt work for some reason

            //based on the result add it to the allItemsList and the selectedItems
            //also create a chip for it
          });

        }
      }
      // Reset the input value
      if (input) {
        input.value = '';
      }

      this[ctrl].setValue(null);
    }
  }

  selected(event: MatAutocompleteSelectedEvent, selectedItems, inputType, ctrl): void {
    this[selectedItems].push(event.option.viewValue);
    this[inputType].nativeElement.value = '';
    this[ctrl].setValue(null);
  }


ВЕСЬ файл


import { Component, OnInit, ElementRef, ViewChild, Inject } from '@angular/core';
import { FormBuilder, FormGroup, Validators, NgForm, FormControl } from '@angular/forms';
import { Router, ActivatedRoute, ParamMap } from '@angular/router';
import { ApiService } from '../../api.service';
import { forkJoin, Observable } from 'rxjs';
import { map, startWith, filter } from 'rxjs/operators';
import {  MatChipsModule, MatAutocompleteSelectedEvent, MatChipInputEvent, MatAutocomplete, MatAutocompleteTrigger  } from '@angular/material'
import {COMMA, ENTER} from '@angular/cdk/keycodes';
import {MatDialog, MatDialogRef, MAT_DIALOG_DATA} from '@angular/material';
import { DialogComponent } from '../../shared/dialog/dialog.component';
import { DialogQuestionService } from '../../shared/dialog/dialog-question.service';
import { a } from '@angular/core/src/render3';

@Component({
  selector: 'app-item-create',
  templateUrl: './item-create.component.html',
  styleUrls: ['./item-create.component.css'],
  providers:[DialogQuestionService]
})

export class ItemCreateComponent implements OnInit {

  visible = true;
  selectable = true;
  removable = true;
  addOnBlur = true;

  readonly separatorKeysCodes: number[] = [ENTER, COMMA];

  itemCreateForm: FormGroup;

  modifierCtrl = new FormControl();
  optionCtrl = new FormControl();

  filteredModifiers: Observable<string[]>;
  filteredOptions: Observable<string[]>;

  categoryList: any[] = [];
  optionList: any[] = [];       //string[] = ['White Bread', 'Wheat Bread', 'Extra Mayo', 'Mustard', 'Grilled Onions', 'Toasted'];
  modifierList: string[] = [];  //string[] = ['Add Bacon', 'Add Avocado', 'Double Meat', 'Double Cheese'];
  taxList: any;                 //string[] = ['Defaut Tax', 'Dine-in Tax', 'Hot Food Tax'];
  componentList: any;           //string[] = ['White Bread', 'Wheat Bread', 'Mayo', 'Turkey', 'Ham', 'Lettuce', 'Tomato', 'Onions'];
  typeList: any;
  //item = {};
  selectedModifiers: string[] = [];
  selectedOptions: any[] = [];

  pageType = 'Create';
  id = this.route.snapshot.params['id'];
  formData:any;
  //dialogQuestions:any;

  @ViewChild(MatAutocompleteTrigger) autocomplete: MatAutocompleteTrigger;

  @ViewChild('modifierInput') modifierInput: ElementRef<HTMLInputElement>;
  @ViewChild('optionInput') optionInput: ElementRef<HTMLInputElement>;

  // @ViewChild('auto') matAutocomplete: MatAutocomplete; //remove this
  @ViewChild('autoModifier') autoModifier:MatAutocomplete;
  // @ViewChild('autoOption') optionMatAutoComplete: MatAutocomplete;

  constructor(
    public service: DialogQuestionService,
    private router: Router,
    private route: ActivatedRoute,
    private api: ApiService,
    private fb: FormBuilder,
    public dialog: MatDialog
    ){
      //if the appropriate filters list is empty THEN open the modal in add()
    this.filteredModifiers = this.modifierCtrl.valueChanges.pipe( 
      startWith(null),
      map((modifier: string | null) => modifier ? this._filter(modifier, 'modifierList') : this.modifierList.slice() )
    );

    this.filteredOptions = this.optionCtrl.valueChanges.pipe( 
      startWith(null),
      map((option: string | null) => option ? this._filter(option, 'optionList') : this.optionList.slice() )
    );

    this.createForm();
  }

  ngOnInit(){
    this.setupForm(this.id);
  }

  setupForm(id) {
    forkJoin(
      this.api.getAll('Category'),
      this.api.getAll('Modifier'),
      this.api.getAll('Option'),
      this.api.getAll('Tax'),
      this.api.getAll('Component'),
      this.api.getAll('Type')
      ).subscribe(([Categories, Modifiers, Options, Taxes, Components, Types]) => { 
        this.categoryList = Categories.map(c => c.name);
        this.modifierList = Modifiers.map(c => c.name);
        this.optionList = Options.map(c => c.name);
        this.taxList = Taxes.map(c => c.name );
        this.componentList = Components.map(c => c.name);
        this.typeList = Types.map(c => c.name ); 
    });

    if(this.route.snapshot.data.update){
      this.api.get('Item',id).subscribe( item => this.itemCreateForm.patchValue(item) );
      this.pageType = 'Update';
    }
  }

  createForm(){
    this.itemCreateForm = this.fb.group({
      name: '',
      categories: [],
      price: 0, 
      options: [],
      components: [], 
      modifiers: [],
      removals: [], 
      taxes: [],
      description: '', 
      author: '', 
    });
  }

  add(event: MatChipInputEvent, selectedItems, allItemsList, ctrl, type, filteredList): void { 

    const options = {};

      const input = event.input;
      const value = event.value;

      if(!this.autoModifier.isOpen || this[allItemsList].indexOf(value) < 0 ){ // just trying this out for modifiers so far, if it works make a switch or something
      console.log('listy',filteredList, this.autoModifier);



      // Add our new item to both the DB and local selected items
      if ((value || '').trim()) {

        if(!this[allItemsList].includes(value.trim())){
          //in this case it is new

          switch(type){ 

            case 'category': 
              break;

            case 'option': 
              options['Type'] = this.typeList;
              options['Categories'] = this.categoryList;
              break;

            case 'component': 
              options['Options'] = this.optionList;
              options['Categories'] = this.categoryList;
              break;

            case 'modifier':
              options['Additions'] = this.optionList;
              options['Removals'] = this.optionList;
              options['Options'] = this.optionList;
              options['Categories'] = this.categoryList;
              options['Type'] = this.typeList;
              break;

            case 'tax':
              break;

            default:
              break;
          }

          let dialogQuestions = this.service.getQuestions(type, options);
          //open a modal to create that item
          const dialogRef = this.dialog.open(DialogComponent, {
            width: '70%',
            data: {
              dialog: this,
              type: type,
              details:{
                name:value,
                questions: dialogQuestions
              }
            },
          });


          dialogRef.afterClosed().subscribe(result => {
            this[allItemsList].push(result.name);
            this[selectedItems].push(result.name);
            this.autocomplete.closePanel();//this doesnt work for some reason

            //based on the result add it to the allItemsList and the selectedItems
            //also create a chip for it
          });

        }
      }
      // Reset the input value
      if (input) {
        input.value = '';
      }

      this[ctrl].setValue(null);
  }

  remove(item: string, type): void {
    console.log('removing from selected', this, item , type, this[type]);
    const index = this[type].indexOf(item);

    if (index >= 0) {
      this[type].splice(index, 1);
    }
  }

  selected(event: MatAutocompleteSelectedEvent, selectedItems, inputType, ctrl): void {
    console.log('SELECTED HAS FIRED')
    this[selectedItems].push(event.option.viewValue);
    this[inputType].nativeElement.value = '';
    this[ctrl].setValue(null);
  }

  focusOut() {
    //change this to pass in the control as argument
    this.modifierCtrl.disable();
    this.modifierCtrl.enable();
    // this seems to help but now im having issues with focus moving
    // to the first chip when trying to select the input box.
    // its good enough for now
  }

  private _filter(value: string, type): string[] {
    const filterValue = value.toLowerCase();
    return this[type].filter(item => item.toLowerCase().indexOf(filterValue) === 0);
  }

  onFormSubmit(form: NgForm) {
    if (this.pageType === 'Create') {
      console.log('Creating', form)
      this.api.post('Item', form)
        .subscribe(res => {
          console.log('resres',res)
          let id = res['_id'];
          this.router.navigate(['menu/details', id]);
        }, (err) => {
          console.log(err);
        });
    } else if (this.pageType === 'Update') {
      console.log('Updating', form)
      this.api.update('Item', this.id, form)
        .subscribe(res => {
          console.log('resres',res)
          let id = res['_id'];
          this.router.navigate(['menu/details', id]);
        }, (err) => {
          console.log(err);
        });
    }
  }

}


1 Ответ

0 голосов
/ 01 мая 2019

это, кажется, довольно распространенная проблема с компонентом, и это главным образом потому, что когда вы нажимаете ENTER, matChipInputTokenEnd и optionSelected срабатывают. Тогда чип будет добавлен, и вход не будет иметь никакого значения для добавления. Может быть, поэтому вы не получаете обратный вызов для этого метода. В любом случае, проверьте этот ответ, это может помочь:

[https://stackoverflow.com/a/52814543/5625648][1]

Надеюсь, это поможет, ура.

...