Join the Stack Overflow Community
Stack Overflow is a community of 6.6 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

I'm trying to load an array of objects from a JSON and display them in my template with *ngFor in my angular2 app. I'm getting this error Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays..

I've found quite a bit of documentation on this particular error and a fix, but I'm having trouble understanding/translating it into a working fix. From what I understand the *ngFor will only render arrays of data and my home.component is trying to render an object of arrays.

The fix I've read is to write a pipe like this:

@Pipe({ name: 'values',  pure: false })
export class ValuesPipe implements PipeTransform {
  transform(value: any, args: any[] = null): any {
    return Object.keys(value).map(key => value[key]);
  }
}

I've tried this but then I'm getting an error that says compiler.umd.js?9df7:14126Uncaught Error: Unexpected value 'HomeComponent' declared by the module 'AppModule' I've built the pipe directly into my home component so I'm unsure why this is a problem.

Here is my code.

home.component.js

    import { Component, OnInit, Pipe, PipeTransform } from '@angular/core';
import { Project } from './project';

import { ProjectService } from './project.service';

@Component({
  selector: 'home',
  templateUrl: './home.html',
  styleUrls: ['./home.scss'],
  providers: [ProjectService]
})

@Pipe({ name: 'values',  pure: false })
export class ValuesPipe implements PipeTransform {
  transform(value: any, args: any[] = null): any {
    return Object.keys(value).map(key => value[key]);
  }
}

export class HomeComponent implements OnInit {
  errorMessage: string;
  projects: Project[];
  selectedProject: Project;
  mode = 'Observable';

  constructor(private projectService: ProjectService) { }

  ngOnInit() { this.getProjects(); }

  getProjects() {
    this.projectService.getProjects()
      .subscribe(
      projects => this.projects = projects,
      error => this.errorMessage = <any>error);
  }

  onSelect(project: Project): void {
    this.selectedProject = project;
  }
}

projects.service.js

import { Injectable }     from '@angular/core';
import { Http, Response } from '@angular/http';

import { Project } from './project';
import { Observable }     from 'rxjs/Observable';


@Injectable()
export class ProjectService {
  private projectsUrl = 'data/project.json'; // URL to web API

  constructor(private http: Http) { }

  getProjects(): Observable<Project[]> {
    return this.http.get(this.projectsUrl)
      .map(this.extractData)
      .catch(this.handleError);
  }

  private extractData(res: Response) {
    let body = res.json();
    return body.data || {};
  }

  private handleError(error: Response | any) {
    // In a real world app, we might use a remote logging infrastructure
    let errMsg: string;
    if (error instanceof Response) {
      const body = error.json() || '';
      const err = body.error || JSON.stringify(body);
      errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
    } else {
      errMsg = error.message ? error.message : error.toString();
    }
    console.error(errMsg);
    return Observable.throw(errMsg);
  }
}

project.json

 {
  "project": [{
    "title": "The Upper Crust",
    "id": "upper-crust",
    "year": "2016",
    "category": ["Design", "Web Design"],
    "thumbnail": "thumbnails/upper-crust.jpg"
  }, (...)
}

Sorry if the answer is already out there I've spent a few hours last night and this morning trying to solve this issue and can't seem to figure it out. I appreciate your help in advance, I'm new to development and am at a loss with much of this stuff.

share|improve this question
1  
There is no field named datain your json, so your extractData method returns an empty object. This kind of error is very easy to find by just using your debugger. – JB Nizet Oct 27 '16 at 16:59
    
wow.... thank you so much. I guess I didn't even need the pipe I just need to change return body.data || {}; to return body.project || {}; – Jleibham Oct 27 '16 at 17:01
    
You should just really return body.project. Returning an empty object instead of the expected array makes it much harder to diagnose errors than just returning undefined if the body doesn't have a project field. It would become obvious if you specified a return type for your method. – JB Nizet Oct 27 '16 at 19:23

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.