Angular 5 ng-select how to add two values to 'bindLabel'?
Asked Answered
J

6

29

I want to have ng-select with two values in the property bindLabel.
I have something like this:

<ng-select placeholder="{{'TASKS.FOR_WHO' | translate }}"
           name="users" 
           [items]="users" 
           bindLabel="firstName" >

 </ng-select>

But in bind label I want to have bindLabel= firstName + lastName. Like this:

<ng-select placeholder="{{'TASKS.FOR_WHO' | translate }}"
           name="users" 
           [items]="users"
           bindLabel="firstName + lastName">

 </ng-select>

How to achieve this?

Junitajunius answered 19/7, 2018 at 10:27 Comment(5)
have you tried bindLabel="{{ firstName + lastName }}" ?Varve
yeap, doesnt help at allJunitajunius
now i get an errorJunitajunius
just use it like this and check [bindLabel]="firstName + lastName" remove {{}} added beforeVarve
it doesnt work too :(Junitajunius
R
22

ng-select only accepts a string value in the attribute. I may be misunderstanding but I believe that if you say bindLabel="firstName+lastName", ng-select is attempting to reference item[firstNamelastName] which does not exist.

I think your best option is to transform the collection. You can add a .map to the end of your array declaration and use bindLabel="fullName" in your template:

[
  {firstName: "John", lastName: "Doe"},
  {firstName: "Jane", lastName: "Doe"}
].map((i) => { i.fullName = i.firstName + ' ' + i.lastName; return i; });
Rowena answered 19/7, 2018 at 11:4 Comment(1)
If anybody has a demo for this question? plz, help me?Possessory
B
40

It is possible to display it via a custom label and item template:

<ng-select [items]="users" bindLabel="firstName"> 

  <ng-template ng-label-tmp let-item="item">
      <span >{{ item.firstName + ' ' + item.lastName }}</span>
  </ng-template>
  <ng-template ng-option-tmp let-item="item" let-search="searchTerm" let-index="index">
        <span >{{ item.firstName + ' ' + item.lastName }}</span>
  </ng-template>

</ng-select>
Busman answered 10/6, 2019 at 18:13 Comment(4)
it is work, but remove button can't show on selected item.Cynde
This should have been the accepted answer. It solves the problem as far as the custom label is concerned.Cholecystotomy
This answer was really helpful and fun. Thank you.Keishakeisling
This helped me find the problem with my ng-template where the options were blank, but, the selected displayed correctly. I only had ng-label-tmp in ng-template. I added ng-option-tmp and both options and selected displayed correctly.Piece
R
22

ng-select only accepts a string value in the attribute. I may be misunderstanding but I believe that if you say bindLabel="firstName+lastName", ng-select is attempting to reference item[firstNamelastName] which does not exist.

I think your best option is to transform the collection. You can add a .map to the end of your array declaration and use bindLabel="fullName" in your template:

[
  {firstName: "John", lastName: "Doe"},
  {firstName: "Jane", lastName: "Doe"}
].map((i) => { i.fullName = i.firstName + ' ' + i.lastName; return i; });
Rowena answered 19/7, 2018 at 11:4 Comment(1)
If anybody has a demo for this question? plz, help me?Possessory
I
9
<ng-select [items]="users" bindLabel="firstName"> 
    <ng-template ng-label-tmp let-item="item" let-clear="clear">
        <span class="ng-value-label">{{item.firstName + ' ' + item.lastName}}</span>
        <span class="ng-value-icon right" (click)="clear(item)">×</span>
    </ng-template>
</ng-select>
Inhospitable answered 11/8, 2020 at 10:29 Comment(1)
This answer is interesting as it adds the clear action on the label, but you should definitely add an explanation.Reborn
H
2

If you want to return custom value , the easiest way to do is to define bindLabel="fullName" and return value from component, for example:

this.adaptedLoans = this.adaptedLoans.map(item => {
    return {
        "id": item.customer.id,
        "name": item.customer.name,
        "creditLimit": item.creditLimit,
        "creditor": item.creditor,
        "fullName": item.creditLimit + ' ' + 'CHF' + ' ' + this.translate.instant('filter_at') + ' ' + item.customer.name
    }
});
Hagfish answered 6/11, 2019 at 8:4 Comment(0)
T
1

I know this is an old one, but here's a bit generic component (can be easily extended to be fully generic) that allows search by multiple fields.
StackBlitz link
Full component:

@Component({
  selector: "app-generic-select",
  template: `
    <ng-select
      [formControl]="control"
      class="select-control"
      id="item-select"
      [items]="adjustedAvailableItems"
      [multiple]="true"
      [closeOnSelect]="false"
      [clearSearchOnAdd]="true"
      [hideSelected]="true"
      bindLabel="searchField"
    >
      <ng-template ng-multi-label-tmp let-items="items" let-clear="clear">
        <div class="ng-value" *ngFor="let item of items">
          <span
            class="ng-value-icon left"
            (click)="clear(item)"
            aria-hidden="true"
            >×</span
          >
          <span class="ng-value-label">{{ getText(item) }}</span>
        </div>
      </ng-template>

      <ng-template ng-option-tmp let-item="item">
        {{ getText(item) }}
      </ng-template>
    </ng-select>
  `
})
export class GenericSelectComponent implements OnChanges {
  @Input() control: FormControl;
  @Input() availableItems: any[];
  @Input() printContent: (item) => string;
  @Input() itemSearchFields: string[];

  adjustedAvailableItems: any[];

  constructor() {}

  ngOnChanges(changes: SimpleChanges) {
    if (changes.itemSearchFields || changes.availableItems) {
      this.adjustedAvailableItems = this.adjustAvailableItems(
        this.availableItems
      );
    }
  }

  private adjustAvailableItems(items: any[]): any[] {
    if (!this.itemSearchFields || !this.itemSearchFields.length) {
      return items;
    }
    return items.map(item => {
      item.searchField = this.itemSearchFields
        .map(searchField => item[searchField])
        .reduce((curr, next) => curr + " " + next);
      return item;
    });
  }

  getText(item: any): string {
    if (!item) {
      return "";
    }
    if (!this.printContent) {
      return item.toString();
    }
    return this.printContent(item);
  }
}

usage:


@Component({
  selector: "my-app",
  template: `
    <app-generic-select
      [availableItems]="availableAccounts"
      [control]="accountControl"
      [itemSearchFields]="['name', 'country']"
      [printContent]="accountText"
    >
    </app-generic-select>
    {{ accountForm.value | json }}
  `
})
export class AppComponent implements OnInit {
  accountForm: FormGroup;

  availableAccounts: Account[] = [];
  delayedObservable = Observable.of(this.getTestAccounts()).delay(3000);

  constructor(private formBuilder: FormBuilder) {}

  ngOnInit(): void {
    this.accountForm = this.formBuilder.group({
      accounts: [[], []]
    });
    this.delayedObservable.subscribe(
      accounts => (this.availableAccounts = accounts)
    );
  }

  get accountControl(): FormControl {
    return this.accountForm.get("accounts") as FormControl;
  }

  accountText = (item: Account): string => {
    return item.name + " - " + item.country;
  };

  getTestAccounts(): Account[] {
    return [
      {
        name: "Adam",
        email: "[email protected]",
        age: 12,
        country: "United States"
      },
      {
        name: "Samantha",
        email: "[email protected]",
        age: 30,
        country: "United States"
      },
      {
        name: "Amalie",
        email: "[email protected]",
        age: 12,
        country: "Argentina"
      },
      {
        name: "Estefanía",
        email: "[email protected]",
        age: 21,
        country: "Argentina"
      },
      {
        name: "Adrian",
        email: "[email protected]",
        age: 21,
        country: "Ecuador"
      },
      {
        name: "Wladimir",
        email: "[email protected]",
        age: 30,
        country: "Ecuador"
      },
      {
        name: "Natasha",
        email: "[email protected]",
        age: 54,
        country: "Ecuador"
      },
      {
        name: "Nicole",
        email: "[email protected]",
        age: 43,
        country: "Colombia"
      },
      {
        name: "Michael",
        email: "[email protected]",
        age: 15,
        country: "Colombia"
      },
      {
        name: "Nicolás",
        email: "[email protected]",
        age: 43,
        country: "Colombia"
      }
    ];
  }
}

Threadgill answered 30/7, 2020 at 11:28 Comment(0)
D
0

I had a similar problem, basically I wanted a dual filter where a number would filter by "code" and a text by 'description'. And I wanted to show 'code - description' on label. The solution to show the value was using the ng-template (as in the higher score answer) and using a variable as the bindLabel value:

      bindLabel="{{ type }}"

So inside the .ts I would:

if (shouldBeCode) {
    this.type = 'code'
} else {
    this.type = 'description'
}

In my case this if is inside a custom search function:

<ng-select
    [items]="filteredList"
    (search)="filter($event)"
    bindLabel="{{ type }}"
    ...
>
Disjointed answered 28/9, 2023 at 17:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.