简体   繁体   English

仅添加选定的芯片

[英]Add ONLY the selected chip

My goal is to add a chip that has been selected.我的目标是添加已选择的芯片。 If there is no option, a chip should be added by the value which has been typed.如果没有选项,则应按已键入的值添加筹码。

All <mat-option> values are from my database.所有<mat-option>值都来自我的数据库。 My problem is that if I type something and there is an option selected, it will add 2 chips.我的问题是,如果我输入一些内容并选择了一个选项,它将添加 2 个筹码。

Example例子

The value JavaScript exists in my database and it will be displayed as <mat-option> .我的数据库中存在值JavaScript ,它将显示为<mat-option> If I type Java (it could also be J ), JavaScript will be selected.如果我输入Java (也可以是J ),将选择JavaScript So what I want is to add the chip JavaScript only (since it is selected) but not both of them.所以我想要的是只添加芯片JavaScript (因为它被选中)但不是两者都添加。 This is how it looks like:这是它的样子:

在此处输入图像描述

HTML HTML

<mat-grid-tile [formGroup]="this.primaryFormGroup">
  <mat-chip-list #chipList>
    <mat-chip *ngFor="let currentTechnology of currentTechnologies" [selectable]="selectable"
              [removable]="removable" (removed)="remove(currentTechnology)">
      {{currentTechnology.name}}
      <mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
    </mat-chip>
    <label>
      <input #techInput
             (keyup)="onKeyUp($event)"
             [matAutocomplete]="auto"
             [matChipInputFor]="chipList"
             [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
             [matChipInputAddOnBlur]="addOnBlur"
             (matChipInputTokenEnd)="add($event)"
             placeholder="Technologies"
             name="technologies"
             formControlName="technologies"
      >
    </label>
  </mat-chip-list>

    <mat-autocomplete autoActiveFirstOption #auto="matAutocomplete" (optionSelected)="selected($event)">
      <mat-option *ngFor="let data of technologies" [value]="data.technology">
        <span matBadge="{{data.counter}}" matBadgeOverlap="false">{{data.technology}} </span>
      </mat-option>
    </mat-autocomplete>
</mat-grid-tile>

TypeScript TypeScript

import {Component, ElementRef, Input, OnInit, ViewChild} from '@angular/core';
import {COMMA, ENTER, SPACE, TAB} from '@angular/cdk/keycodes';
import {MatAutocomplete, MatAutocompleteSelectedEvent, MatChipInputEvent} from '@angular/material';
import {TechnologiesService} from './technologies.service';
import {SelectionService} from '../sections/selection.service';
import {FormBuilder, FormControl, NgForm, Validators} from '@angular/forms';
import countries from '../../../assets/json/countries.json';

@Component({
  selector: 'app-form',
  templateUrl: './form.component.html',
  styleUrls: ['./form.component.sass']
})
export class FormComponent implements OnInit {
  @ViewChild('techInput', {static: false}) techInput: ElementRef<HTMLInputElement>;
  @ViewChild('auto', {static: false}) matAutocomplete: MatAutocomplete;
  @ViewChild('customForm', {static: true}) customForm: NgForm;
  @Input() section: string;

  separatorKeysCodes = [COMMA, SPACE, TAB, ENTER];
  selectable = false;
  removable = true;
  addOnBlur = true;
  technologies = [];
  setTechnologies;
  currentTechnologies = [];
  minDate = new Date();
  countries = countries;

  // Primary form group
  primaryFormGroup = this.fb.group({
    title: '',
    description: '',
    gender: '',
    city: '',
    country: '',
    language: '',
    highestEducation: '',
    dateOfBirth: '',
    workload: '',
    typeOfTask: '',
    hourlyRate: '',
    paymentTime: '',
    minPrice: '',
    maxPrice: '',
    deadlineFrom: '',
    deadlineUntil: '',
    technologies: '',
    milestones: [false, Validators.requiredTrue]
  });
  // Important form group
  importantFormGroup = this.fb.group({
    gender: [false, Validators.requiredTrue],
    city: [false, Validators.requiredTrue],
    country: [false, Validators.requiredTrue],
    language: [false, Validators.requiredTrue],
    highestEducation: [false, Validators.requiredTrue],
    dateOfBirth: [false, Validators.requiredTrue],
    workload: [false, Validators.requiredTrue],
    hourlyRate: [false, Validators.requiredTrue],
    paymentTime: [false, Validators.requiredTrue]
  });

  constructor(private technologiesService: TechnologiesService, private selection: SelectionService, private fb: FormBuilder) {}

  // Form Control
  required = new FormControl('', Validators.required);
  hourlyRate = new FormControl('', Validators.max(200));

  ngOnInit() {
    // Set the min date
    this.minDate = new Date(this.minDate.getFullYear(), this.minDate.getMonth(), this.minDate.getDate());

    // Modify the form object
    this.primaryFormGroup.valueChanges.subscribe(inputFields => {
      if (inputFields) {
        // Change technologies
        if (inputFields.technologies) {
          // inputFields.technologies = Array.from(this.setTechnologies);
          // delete inputFields.technologies;
        }
        // Change type-of-task
        const typeOfTask = inputFields.typeOfTask;
        if (typeOfTask) {
          if (typeOfTask === 'project') {
            inputFields.project = 1;
          } else if (typeOfTask === 'feature') {
            inputFields.feature = 1;
          } else if (typeOfTask === 'bugfix') {
            inputFields.bugfix = 1;
          } else if (typeOfTask === 'other') {
            inputFields.other = 1;
          }
          delete inputFields.typeOfTask;
        }
        // Change tech
        const inputEntries = Object.entries(inputFields).filter(([key, value]) => value);
        // console.log('result:', inputEntries);
      }
    });
  }

  // Get the current section
  getSelectedSection() {
    return this.selection.getSection();
  }

  // On Key up, show technologies
   onKeyUp(event: any): void {
    if (event.target.value.trim().length > 0) {
      this.technologiesService.getTechnologies(event.target.value)
        .subscribe(data => {
          if (JSON.stringify(this.technologies) !== JSON.stringify(data)) {
            this.technologies = data;
          }
        });
    }
  }

  // On enter, add technology
  onEnter(evt: any) {
    if (evt.source.selected) {
      this.add(evt.source);
      evt.source.value = '';
    }
  }
  // Add technologies
  add(event: MatChipInputEvent): void {
    if (!this.matAutocomplete.isOpen) {
      console.log('add');
      const input = event.input;
      const value = event.value;

      if ((value || '').trim()) {
        // E.g., { "name": "Java" }
        this.currentTechnologies.push({name: value.trim()});
        // Set technologies without keys
        if (this.setTechnologies) {
          this.setTechnologies.add(value);
        } else {
          this.setTechnologies = new Set();
          this.setTechnologies.add(value);
        }
      }

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

  // Select the autocomplete
  selected(event: MatAutocompleteSelectedEvent): void {
    console.log('select');
    if (!JSON.stringify(this.currentTechnologies).includes(`{"name":"${this.techInput.nativeElement.value.trim()}"`)) {
      this.currentTechnologies.push({name: this.techInput.nativeElement.value.trim()});
      this.techInput.nativeElement.value = '';
    }
  }

  // Remove technology
  remove(tech: any): void {
    const index = this.currentTechnologies.indexOf(tech);

    if (index >= 0) {
      this.currentTechnologies.splice(index, 1);
    }
  }

}

I think the main problem is that if I select an option, both functions ( selected() and add() ) will be executed.我认为主要问题是,如果我选择 select 一个选项,两个函数( selected()add() )都将被执行。 As you see, I have already tried it with this.matAutocomplete.isOpen but the return is ALWAYS false.如您所见,我已经使用this.matAutocomplete.isOpen进行了尝试,但返回总是错误的。

I have found an example on Stackblitz , which works exactly the way I want it.我在Stackblitz上找到了一个示例,它完全按照我想要的方式工作。 But I have spent more than 10 hours to fix my code to make it work the same but I have NO IDEA what exactly is wrong with my code.但是我花了 10 多个小时来修复我的代码以使其工作相同,但我不知道我的代码到底有什么问题。

If you have an idea what it could be, I would REALLY appreciate it!如果您知道它可能是什么,我将非常感激!

Updates更新

  • If I remove this.currentTechnologies.push({name: value.trim()});如果我删除this.currentTechnologies.push({name: value.trim()}); (in function add() ), ONLY the selected option will be added, which is good but if I type anything else which is not in my array technologies , that will not be added. (在 function add()中),只会添加选定的选项,这很好,但如果我键入不在我的数组technologies中的任何其他内容,则不会添加。
  • If I remove this.currentTechnologies.push({name: this.techInput.nativeElement.value.trim()});如果我删除this.currentTechnologies.push({name: this.techInput.nativeElement.value.trim()}); (in function selected() ), only the value that I have typed will be added. (在 function selected()中),只会添加我输入的值。

Try to remove the addOnBlur option or set it to false in yout ts file.尝试删除 addOnBlur 选项或在 yout ts 文件中将其设置为 false。 That worked for me!这对我有用!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM