1

I'm trying to display a list of Contacts in a list:

<h1>Contacts</h1>
<ul>
    <li *ngFor="let contact of contacts$ | async">
        <ul>
            <h1>Name: {{contact.name}}</h1>
            <li>ObjectID: {{contact._id}}</li>
            <li>LastName: {{contact.lastName}}</li>
            <li>FirstName: {{contact.firstName}}</li>
            <li>Email: {{contact.email}}</li>
            <li>Notes:
                <ul *ngFor="let note of contact.notes">
                    <li>{{note}}</li>
                </ul>
            </li>
        </ul>
    </li>
</ul>

contacts$ is an Observable<Array<Object>>:

@Component({
    selector: 'contacts-list',
    templateUrl: 'list.component.html'
})
export class ContactsListComponent implements OnInit {
    contacts$: Observable<Array<Object>>;


    constructor(private logger: LoggerService,
                private router: Router,
                private trackerService: TrackerService) {
        this.logger.debug(`ContactListComponent.ctor`);
    }

    ngOnInit() {
        this.contacts$ = this.trackerService.cache('tracker/contacts');
    }
}

For now, TrackerService.cache(...) is simply creating an Observable froma hardcoded array, for testing:

public cache(path: string): Observable<Array<Object>> {
    let retval = [new Object({
        _id: '123abc',
        lastName: 'last',
        firstName: 'first',
        email: '[email protected]',
        notes: ['note 1', 'note 2']
    }), new Object({
        _id: '123abc',
        lastName: 'last',
        firstName: 'first',
        email: '[email protected]',
        notes: ['note 1', 'note 2']
    })];
    return Observable.from(retval)
        .map((v) => {
            this.logger.debug(`Mapping value: ${JSON.stringify(v)}`);
            return v;
        });
}

The .map() operation is just for testing, and I see this in the chrome console:

debug DEBUG: Mapping value: {"_id":"123abc","lastName":"last","firstName":"first","email":"[email protected]","notes":["note 1","note 2"]}

However when I run this, I'm getting:

Error: Error in ./ContactsListComponent class ContactsListComponent - inline template:2:8 caused by: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.

I've read other SO threads, angular.io, and my ng2-book which has similar examples, but I'm just not figuring this out.

What am I doing wrong?

5
  • so do you get desire data in console? Commented Jan 16, 2017 at 14:08
  • this.contacts$.subscribe(value => this.contact = value); after this.contacts$ = this.trackerService.cache('tracker/contacts'); and in *ngFor replace contacts$ | async with contact. declare a contact: any . you need to subscribe to observable Commented Jan 16, 2017 at 14:12
  • @AmitSuhag: I thought the async pipe handled the subscription for me? Isn't that the whole point of the async pipe? Commented Jan 16, 2017 at 14:55
  • @micronyks: I see the output to the debug log from the map call, but I do the template is not rendered. Commented Jan 16, 2017 at 14:55
  • I dont thing that you are getting array in result. its just a json object that your are getting. right? Commented Jan 16, 2017 at 15:26

1 Answer 1

1

Observable.from will emit each element of the array.

Use Observable.of to emit the whole array.

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

3 Comments

That was the problem. @micronyks' comment led me to the solution as well, and I was just about to post an answer.
I guess that raises a question, however. In my original code where I was using from, my .map() function was only being hit once, for one element of the array. If from emits each element of the array, why did I only see one in my debug output?
Hm, that's strange indeed. You should see two logs. A possibility is that, since your two objects are equals, the log generated is the same. In such case, chrome console just print the log once, but adds a count on the left of the printed log. In your case you could see something like (2) Mapping value ....

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.