Autocomplete displayValue and manually set value


Topic: Autocomplete displayValue and manually set value

Fiducial asked 5 years ago

Hi,

I'm using the mdbautocomplete with a server side search. When user selects something, i want to keep the UserSelected object, and write the FullName in the field. So i used "displayValue" for that purpose. Template-driven form .html:

 <div class="md-form">
          <input #userInput="ngModel" type="text" class="completer-input form-control " [(ngModel)]="SearchText" [mdbAutoCompleter]="auto"
                 placeholder="Nom ou matricule" (focusout)="OnLeave()"/>
          <mdb-auto-completer #auto="mdbAutoCompleter" [displayValue]="displayFn" >
            <mdb-option *ngFor="let user of userList" [value]="user">
              <div class="d-flex flex-column">
                <span><strong>{{ user.FullName }}</strong></span>
                <span>{{ user.Societe }}</span>
              </div>
            </mdb-option>
          </mdb-auto-completer>
</div>

TS file:

 OnLeave() {

        if (this.userInput.value === '') {
          this.SelectedUser = null;
        }

        this.SearchText = this.SelectedUser;

      }

      displayFn(user): string {
        return user && user.FullName ? user.FullName : '';
      }

ngAfterViewInit(): void {
    this.userInput
      .valueChanges
      .pipe(debounceTime(300), filter(theNewValue => typeof theNewValue === 'string'))
      .subscribe(theNewValue => {
        this.searchUser(theNewValue);
      });

    this.userInput
      .valueChanges
      .pipe(filter(theNewValue => typeof theNewValue !== 'string'))
      .subscribe(theNewValue => {
        this.SelectedUser = theNewValue;        
      });
  }

With this, i can keep track of the latest selecteduser, and the actual search text. If the user change the search text, but does not select anyone, and leave the text, i would like to put back the name of the previous selected user (as a 'cancel search' would do)

But when i do: this.SearchText = this.SelectedUser; i get [Object object] in the field instead of the actual FullName, (displayValue function is not called)

What am i doing wrong?

Thanks!


Arkadiusz Idzikowski staff commented 5 years ago

Can you prepare a simple example with static data and full html/ts code so we can reproduce that on our end?


Fiducial answered 5 years ago

Hi, Here are the request files with a simple static example: [HTML]:

<div class="md-form">
  <input #userInput2="ngModel" type="text" class="completer-input form-control " [(ngModel)]="SearchText" [mdbAutoCompleter]="auto2"
         placeholder="Nom ou matricule" (focusout)="OnLeave()"/>
  <mdb-auto-completer #auto2="mdbAutoCompleter" [displayValue]="displayFn"  >
    <mdb-option *ngFor="let user of userList" [value]="user">
      <div class="d-flex flex-column">
        <span><strong>{{ user.FullName }}</strong></span>
      </div>
    </mdb-option>
  </mdb-auto-completer>
</div>

[TS]

import {AfterViewInit, Component, OnInit, ViewChild} from '@angular/core';
import {debounceTime, filter} from 'rxjs/operators';

@Component({
  selector: 'app-test-mdb-autocomplete',
  templateUrl: './test-mdb-autocomplete.component.html',
  styleUrls: ['./test-mdb-autocomplete.component.css']
})
export class TestMdbAutocompleteComponent implements OnInit,AfterViewInit {

  constructor() {
  }

  userStaticList = [
    {FullName: 'Marine', ID: '1'},
    {FullName: 'Fred', ID: '2'},
    {FullName: 'Marinette', ID: '3'},
    {FullName: 'Marilou', ID: '4' }
    ];
  userList = [];
  @ViewChild('userInput2') private userInput2;

  SearchText = '';
  SelectedUser: null;

  ngOnInit(): void {
    //Render [object Object] instead of user.FullName (Marine) in the search field
    //displayFn not called
    this.SearchText = this.userStaticList[0];
  }

  ngAfterViewInit() {
    this.userInput2.valueChanges
      .pipe(debounceTime(300),
        filter(val => typeof val === 'string')
      ).subscribe(val => {
        this.userList = [];
        this.userStaticList.forEach(elem => {
          if (elem.FullName.toLowerCase().startsWith(val.toString().toLowerCase())) {
            this.userList.push(elem);
          }
        });
      }
    );

    this.userInput2
      .valueChanges
      .pipe(filter(theNewValue => typeof theNewValue !== 'string'))
      .subscribe(theNewValue => {
          this.SelectedUser = theNewValue;
        });

  }

  displayFn(user) {
    let nameOfUser= (user ? user.FullName : '');
    console.log('DisplayFn:'+user);
    console.log('DisplayFn returned value:'+nameOfUser);
    return nameOfUser;
  }

  OnLeave() {
    if (this.userInput2.value) {
      if (this.SelectedUser) {
        this.SearchText = this.SelectedUser;
      } else {
        this.SearchText = '';
      }
    }else
    {
      this.SelectedUser=null;
    }
  }
}

Thanks


Arkadiusz Idzikowski staff answered 5 years ago

In this case SearchText should be of type string and you try to overwrite it with object here:

this.SearchText = this.userStaticList[0];

and here:

this.SearchText = this.SelectedUser;

In your case it should look like this:

this.SearchText = this.userStaticList[0].FullName;
this.SearchText = this.SelectedUser.FullName;

If you don't use TSLint it is good idea to configure it in your IDE/Code editor, because it will automatically let you know about problems with types.


Please insert min. 20 characters.

FREE CONSULTATION

Hire our experts to build a dedicated project. We'll analyze your business requirements, for free.

Status

Answered

Specification of the issue
  • User: Free
  • Premium support: No
  • Technology: MDB Angular
  • MDB Version: 9.0.1
  • Device: PC
  • Browser: Chromium
  • OS: WIndows
  • Provided sample code: No
  • Provided link: No