0

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();

3 Answers 3

2

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();
}); 
Sign up to request clarification or add additional context in comments.

8 Comments

Thank you for this but it is still not appearing in the UI.
@GeraldGonzales can you put a console.log like I did in my answer and add the log to your question please?
It logged the array object.
@GeraldGonzales can you add what it logged to your question please?
@GeraldGonzales as you would appreciate it is hard to tell something from that response. What are the contents of those objects when you click on them in the console?
|
2

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.

Comments

1

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');

5 Comments

If the async operation takes longer then 200ms for some reason, like unexpected latency in the network, then this will not work. It might be acceptable in some cases, but if the application depends on this dropdown to function properly then a more robust implementation is required.
Man , please read my second para , you can init on viewInit and then reinit on when you get data. @unitario , hope you get your answer
May I know how to destroy and reinit my select?
Updated my answer , please go through the link also you will get better idea
@GeraldGonzales You need a way to know when the view and *ngFor has been fully rendered before you instantiate it. Since *ngFor requires some time to complete it will not work simply adding it after the data request is complete. I was struggling with the same problem and in my answer outlines how I solved it. It adds complexity to your application and a simple setTimeout might be all you need.

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.