Gerald Gonzales
Gerald Gonzales

Reputation: 533

select option not displaying array of object

I have a dropdown in my component. Here is the code of the component:

export class MyComponent  {

MyObjectArray: MyObject[] = [];

constructor(private _service: MyService)
}

ngOnInit() {
    this._service.get().do((response): MyObject[]) => {
        this.MyObjectArray = response;

        this.MyObjectArray.forEach((obj) => {
            console.log(obj.Code)
        });
    });

My html is:

<select>
    <option [value]="obj.Code" *ngFor="let obj of MyObjectArray; let i = index">{{obj.Code}}</option>
</select>

And in my service:

return this._http.get(_url, this.options)
    .map(res => res.json())
    .catch(super.handlerError);

I have a console.log in my code to verify that the service returned something and I am having results. The issue is why is it not binding on my dropdown. I did inspect element and there are no items in my dropdown.

Oh and one thing, I tried putting the ngFor in a div with span inside, it was working. I just don't understand when I put it on my dropdown it doesn't work.

EDIT

Now when I inspect element, I can see my objects. But they are still not appearing in my dropdown. Here is what I changed:

this._service.get().subscribe(response => this.MyObjectArray = response);

EDIT

I also have this code on my ngAfterViewInit()

$('select').material_select();

Upvotes: 0

Views: 876

Answers (3)

unitario
unitario

Reputation: 6535

You have a dropdown which is constructed using asynchronous data. Then you have $('select').material_select() which instantiates the select and it options.

The problem is that by the time ngAfterViewInit() lifecycle hook is executed the *ngFor operation is still in process. You can pass the select element it and inspect it yourself, my guess it that it will not have any options listed.

I had a similar issue and I solved it by creating a directive, add a reference to it on the *ngFor element, then utilize the built in variable last - let last = last, and pass that as input to the directive.

If last === true then your dropdown is complete and you can instatiate it from the directive using $('select').material_select().

You can also use setTimeout in the hopes of there is no latency in the network that holds things up, in which case the dropdown would not work of course.

Upvotes: 2

Vivek Doshi
Vivek Doshi

Reputation: 58573

Replace your code with this:

this._service.get().subscribe(response => {
        this.MyObjectArray = response;
        setTimeout(function(){
            $('select').material_select();
        },200);
}); 

Code : $('select').material_select(); should init the select box after value init , or you can init on ngAfterViewInit but then you have to destroy and reinit on the time you get the data.

You are getting data correctly but the issue is you are initialising the select box before you get the data , so it will not auto update select coz you have already manipulated it with jQuery , you have to reinit , to show updated data.


How to destroy select 2 : http://materializecss.com/forms.html

$('select').material_select('destroy');

Upvotes: 1

eko
eko

Reputation: 40647

Try triggering change detection manually:

import { ChangeDetectorRef } from '@angular/core';

constructor(private cdr: ChangeDetectorRef){...}

this._service.get().subscribe(response => {
        console.log(JSON.stringify(response)); // what does this print
        this.MyObjectArray = response;
        this.cdr.detectChanges();
}); 

Upvotes: 2

Related Questions