LeaVerou / awesomplete

Ultra lightweight, usable, beautiful autocomplete with zero dependencies.
http://leaverou.github.io/awesomplete/
MIT License
6.97k stars 611 forks source link

Input displayed text different form control selected value #17197

Open Rui90 opened 5 years ago

Rui90 commented 5 years ago

I have the following autocomplete which uses the awesomplete plugin. The thing is this is an autocomplete, where the value selected is different from the label that should be showned.

   <input
      id="{{options.elementId}}"
      #autocomplete
      class="c-awesomplete__input dropdown-input"
      [formControl]="control"
      [label]="options.label"
      (click)="toggleDropdown()">

Awesomplete component:

import { AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild } from "@angular/core";

import Awesomplete from "awesomplete";
import { FormControl } from "@angular/forms";
import { IAwesompleteOptions } from "@core-module/interfaces/awesomeplete/iawesomplete-options.interface";

@Component({
  selector: "awesomplete",
  templateUrl: "./awesomplete.component.html",
  styleUrls: ["./awesomplete.component.scss"],
  host: {class: "c-awesomplete"}
})
export class AwesompleteComponent implements OnInit, AfterViewInit {

  @ViewChild("awesomplete", {static: false}) public awesompleteRef: ElementRef;
  @Input() public control: FormControl;
  @Input() public options: IAwesompleteOptions;
  public awesomplete: Awesomplete;

  constructor() { }

  ngOnInit() {
    this.control.enable();
  }

  ngAfterViewInit() {
    this.awesomplete = new Awesomplete(this.awesompleteRef.nativeElement, this.options);
    this.awesomplete.input.addEventListener("awesomplete-selectcomplete", (event) => {
      this.control.setValue(event.target.value);
    });
  }

  public toggleDropdown(): void {
    this.awesomplete.evaluate();
    this.awesomplete.open();
  }

  public clearText(): void {
    this.control.setValue("");
  }

}

And this are the options that I'm passing to the component:

this.options = { 
      minChars: 0,
      list: [
        { label: "brasil", value: "br"},
        { label: "portugal", value: "pt"},
        { label: "france", value: "fr"},
      ]
}

So when I click the Input I have a list of Brasil, Portugal, France and when I choose one, for instance, France, what I see on the input is fr. I want the control to have the fr value, but I want the input to display France.

Rui90 commented 5 years ago

heeeeelp

I need somebody heeeelp

hmvella commented 5 years ago

Just encountered the same issue and came here looking for a more elegant solution.

A hacky solution I'm using at the moment is to include the necessary text for the search to work within the label, and then hide it using css. Forexample:

<style>
.hidden{
 display: none;
}
</style>

...

list: [
        { label: "brasil<span class="hidden"> br</span>", value: "br"},
        { label: "portugal<span class="hidden"> pt</span>", value: "pt"},
        { label: "france<span class="hidden"> fr</span>", value: "fr"},
      ]

If anyone has a cleaner solution, I'm all ears!

EDIT: To clean the label text and prevent it from inserting the span into your input as plaintext, you can use the replace function as follows:


let awesomplete = new Awesomplete(elem, {
    minChars: 0,
    autoFirst: false,
    list: [],
    replace: function (text) {
        let result = extractNameFromResult(text);
        this.input.value = result;
    }
});

function extractNameFromResult(text) {
    const index = text.indexOf('<span class="hidden">');
    const result = text.substr(0, index);
    return result;
}
Rui90 commented 5 years ago

I've basically made a "serialize" "deserialize" so my list only has labels, and when I'm about to save I just parse to the key.... Not good, but, works