1

I am trying to display items in dropdown using ng-select in Angular 5. But the dropdown component that I am designing should be more generic in nature meaning people who are calling my dropdown should be able to pass customized template for displaying items in dropdown. i.e. the items list in dropdown should be build with specific template and a call to my generic dropdown should display the customized list of items. Is this something that can be achieved in transclusion? Currently I am using "dropdownVal" which is of String[] datatype but instead I need to have array of template/component.

My code is below

dropdown.component.ts

@Component({
  selector: 'wdsk-dropdown',
  templateUrl: './dropdown.component.html',
  styleUrls: ['./dropdown.component.scss']
})
export class DropdownComponent implements OnInit {


  @Input() dropdownVal: string[];
  @Input() placeholder: string;

  @Output() selectedItem = new EventEmitter();

  constructor() { }

  ngOnInit() {
  }

  onSelect(value: any) {
    this.selectedItem.emit(value);
  }
}

Template - dropdown.component.html

<div class="col-md-12 account-dropdown">
  <div class="form-group row">

    <div class="col-md-12">

      <ngx-select tabindex="0" placeholder={{placeholder}} [items]="dropdownVal" (selected)="onSelect($event)">
      </ngx-select>
    </div>
  </div>
</div>
5
  • Just add <ng-content></ng-content> inside the dropdown.component.html wherever you want the customised content to display, and pass whatever you want to display inside the wdsk-dropdown tags Commented Nov 21, 2018 at 20:51
  • i have a solution for this, but it is using the mat-select element from angular-materials... does that count? :) Commented Nov 21, 2018 at 21:03
  • i guess i might share my solution just in case it helps at all Commented Nov 21, 2018 at 21:04
  • Thanks for response but will the data inside <ng-content></ng-content> will appear under dropdown? How to link the [items] directive of ngx-select to the contents of <ng-content></ng-content> so that the data in <ng-content></ng-content> is listed as dropdown items. Also [items] accepts Array of data. Commented Nov 21, 2018 at 21:07
  • 1
    @JBoothUA, please share your solution Commented Nov 21, 2018 at 21:10

1 Answer 1

1

I have done this before with Angular Material's mat-select element, using @ContentChildren and ng-template.

Working Example Here

dropdown.ts

import { Component, OnInit, Input, ViewEncapsulation, Output, EventEmitter, ViewChild, ContentChildren, QueryList , TemplateRef} from '@angular/core';
import { MatSelectChange, MatSelect } from '@angular/material/select';

// Template Sections
@Component({
  selector: 'custom-dropdown-item',
  template: '<ng-template #content><ng-content></ng-content></ng-template>'
})
export class CustomDropdownItemsComponent {
  @ViewChild('content') content: any;
  @Input() value: any;
  @Input() width: string;
  @Input() height: string;
  @Output() click: EventEmitter<any> = new EventEmitter();

  onClick() {
    this.click.emit(this.value);
  }
}

@Component({
  selector: 'custom-dropdown',
  templateUrl: './custom-dropdown.component.html',
  styleUrls: ['./custom-dropdown.component.scss']
})
export class CustomDropdownComponent implements OnInit {
  @ViewChild('matSelect') matSelect: MatSelect;
  @Output() valueChange: EventEmitter<MatSelectChange> = new EventEmitter<MatSelectChange>();
  @Output() openedChange: EventEmitter<boolean> = new EventEmitter<boolean>();
  @Input() value: any;
  @Input() items: string[];
  @Input() placeholder: string;
  @Input() dropdownTitle: string;
  @Input() addDynamicContent: boolean = false;
  @Input() compareWith: Function;
  defaultCompareWithFn: Function = function () { };
  selectedIndex = -1;

  @ContentChildren(CustomDropdownItemsComponent)
  ddItems:QueryList<CustomDropdownItemsComponent>;

  constructor() { }

  ngOnInit() {
  }

  valueChanged(event: MatSelectChange) {
    this.valueChange.emit(event.value);
  }
}

dropdown.html

<mat-select #matSelect [(value)]="value" (selectionChange)="valueChanged($event)">
  <mat-option style="width:100px" [value]="0">
    <h1 style="color:red">I'm content = 0</h1>
  </mat-option>
  <mat-option [style.width]="ddlItem.width" [value]="i+1" *ngFor="let ddlItem of ddItems; let i = index">
    <ng-container [ngTemplateOutlet]="ddlItem.content"></ng-container>
  </mat-option>
</mat-select>

Passing in custom items:

<div class="mat-app-background basic-container" style="width:200px; padding:0; margin:0">
    <custom-dropdown [addDynamicContent]="true" [(value)]="selected">
        <custom-dropdown-item width="100px">
                <span style="color:green">I'm dynamic content = 1</span>
        </custom-dropdown-item>
        <custom-dropdown-item width="100px">
                <p style="color:blue">I'm dynamic content = 2</p>
        </custom-dropdown-item>
    </custom-dropdown>
</div>
<div>
  Selected: {{ selected }}
</div>
Sign up to request clarification or add additional context in comments.

8 Comments

Thanks @JBoothUA, your solution helps but unfortunately I've to implement the same using ngx-select
@Nicolas if you can create a stackblitz with ngx-select i can take a look at it
@Nicolas maybe the same tactics will work with ngx-select?
I'm newbie to this, really not sure if it works but wanted to achieve this with ngx-select.
Can you take a look at my stackblitz ngdropdown
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.