3

I am trying to create a generic drop down control in Angular 2, using Semantic UI. I have the following code:

import {ElementRef, Component, OnInit, EventEmitter} from "angular2/core";
import {DropdownValue} from "./dropdown-value";

declare var jQuery: any;

@Component({
selector: 'my-dropdown',
inputs: ['selectedItem', 'items', 'label'],
outputs: ['selectedItemChange'],
template: `
<div class="field">        
  <label>{{label}}</label>        
    <select class="ui selection dropdown" [ngModel]="selectedItem.value" (ngModelChange)="onChange($event)">
      <!--<option value="" selected>Please Select</option>-->
      <option *ngFor="#item of items" [value]="item.value">{{item.label}}</option>
    </select>        
</div>`
})

export class MyDropdownComponent implements OnInit {

items: DropdownValue[];
selectedItem: DropdownValue;
selectedItemChange: EventEmitter<any> = new EventEmitter();

constructor(private elementRef: ElementRef) {
}

ngOnInit(): any {
    this.items.unshift(new DropdownValue('', 'Please Select'));
    this.selectedItem = this.selectedItem || this.items[0];
    //jQuery(this.elementRef.nativeElement).find('select').dropdown();
}

onChange(newValue) {
    let selectedItem = this.items.find(item => item.value == newValue);
    this.selectedItemChange.emit(selectedItem);
}

}

This actually works just fine as it is (without Semantic UI JS styling), the issue is, as soon as I uncomment the line //jQuery(this.elementRef.nativeElement).find('select').dropdown(); the 'Please Select' is no longer visible and it does not show the initial selection.

2 Answers 2

4

As Günter said, you should call jQuery().dropdown() in ngAfterViewInit().

dropdown() resets the selected value. so you have to reselect the desired value after dropdown():

ngAfterViewInit(){
  jQuery(this.elementRef.nativeElement).find('select').dropdown({allowTab:false});
  jQuery(this.elementRef.nativeElement).find('select').dropdown("set selected",this.selectedItem.value);
}

See plunkr

Sign up to request clarification or add additional context in comments.

Comments

3

Use

setTimeout(() => 
  jQuery(this.elementRef.nativeElement).find('select').dropdown();
}, 1); 

to give Angular some air to breath - update the view to show this.items.unshift

or use ngAfterViewInit(). This way it should work without setTimeout()

ngAfterViewInit() {
  jQuery(this.elementRef.nativeElement).find('select').dropdown();
}

11 Comments

Please elaborate: update the view to show this.items.unshift?
When you add/remove items from an array you (or otherwise change a value bound from the view *ngFor="#item of items"), the view is only updated after the next change detection cycle. Change detection can't run between synchronous executed lines of code. Therefore we reschedule the jQuery call to allow Angular to do change detection and update the HTML and only then jQuery() will find the element there.
If I put the JQuery in a timeout as you suggested, it loses it initial selection. I am setting initial selection on ngOnInit as follows: this.selectedItems = this.items[1];
Can you create a Plunker? I don't use jQuery myself and it's hard to reason about what exactly might be going on from looking at the static code.
I have created a Plunker: link. Please notice that the selected item is not displayed, it only does when you comment out the line: jQuery(this.elementRef.nativeElement).find('select').dropdown();
|

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.