1

can any one please tell me why I can not loop through this array? In ngOnInit, everything works fine. I got an array that I successfully display in the template. But in ngAfterViewInit, console.log show the array but when looping through with "for of" or "forEach", nothing works.

import { JobsService } from '../jobs.service';
import {Job} from '../models/Job';

@Component({
    selector: 'app-job',
    templateUrl: 'job.component.html'
})

export class JobComponent implements OnInit, AfterViewInit {
    title = 'Job';
    jobs: Job[] = [];
    InProcess = '';
    CurrentPartner = '';
    ShowProcess = false;
    sended = '';

    constructor(private jobsService: JobsService) {
    }

    ngOnInit() {
        this.jobs = this.jobsService.getJobs();
    }
    ngAfterViewInit() {
      console.log(this.jobs); // Show the array

      // Nothing happened when looping through the array
      this.jobs.forEach((oneJob) => {
        console.log(oneJob);
      });
    }
}

Screenshot of the console in Google Chrome

The content of the service:

import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import {Job} from './models/Job';

interface IJob {
  message: string;
  jobs: any[];
}

@Injectable({
  providedIn: 'root'
})

export class JobsService {
  constructor(private httpClient: HttpClient) { }
  private REST_API_SERVER = 'http://localhost:8080/myband/api/getjobs.php';
  private REST_API_SERVER_SEND = 'http://localhost:8080/myband/api/sendjob.php';
  jobList: Job[] = [];
  errorMessage: any;
  message: string;

  static handleError(err: HttpErrorResponse) {
    let errorMessage = '';
    if (err.error instanceof ErrorEvent) {
      errorMessage = `An error occurred: ${err.error.message}`;
    } else {
      errorMessage = `Server returned code: ${err.status}, error message is: ${err.message}`;
    }
    console.error(errorMessage);
    return throwError(errorMessage);
  }

  public getJobs() {
    this.requestJobs().subscribe(
      iJob => {
        this.message = iJob.message;
        for (const job of iJob.jobs) {
          const oneJob: Job = new Job(job);
          this.jobList.push(oneJob);
        }
      },
      error => this.errorMessage = error as any
    );
    return this.jobList;
  }

  public requestJobs(): Observable<IJob> {
    return this.httpClient.get<IJob>(this.REST_API_SERVER).pipe(
       catchError(JobsService.handleError)
    );
  }
}

8
  • Can you also print this.jobs. Commented Dec 5, 2019 at 4:18
  • You can see it by clicking the link to the screenshot. Commented Dec 5, 2019 at 4:25
  • Go to your sources tab in DevTools. CTRL + P and type the name of your file. Look if there is your code there. If it is not there, it is cache. Restart your webpack. Commented Dec 5, 2019 at 4:26
  • Thanks @MathiasGhenoAzzolini, I can see my code there. So I still have no idea where the problem come from. Commented Dec 5, 2019 at 4:39
  • can you apply a breakpoint on this.jobs.foreach and check what's the value in this.jobs? Commented Dec 5, 2019 at 4:55

4 Answers 4

1

The first thing I want to say to you is about isolation of responsibilities.

Your service must have just one job: provider one way to access your data; It means your logic inside getJobs() method could be done in your component.

export class JobsService {
    constructor(
        private httpClient: HttpClient,
    ) {}
    private REST_API_SERVER = 'http://localhost:8080/myband/api/getjobs.php';

    public requestJobs(): Observable<IJob> {
        return this.httpClient.get<IJob>(this.REST_API_SERVER);
    }
}

Now, you can handler your data in your component.

import { JobsService } from '../jobs.service';

@Component({
    selector: 'app-job',
    templateUrl: 'job.component.html'
})

export class JobComponent implements OnInit, AfterViewInit {
    title = 'Job';
    jobs$;
    InProcess = '';
    CurrentPartner = '';
    ShowProcess = false;
    sended = '';

    constructor(private jobsService: JobsService) {
    }

    ngOnInit() {
        this.jobs$ = this.jobsService.requestJobs();
    }



    ngAfterViewInit() {
        this.jobs$
            .pipe(
                map(() => {}), // change your data here
                catchError(() => {}) // handler your error here;
            )
            .subscribe(
                () => {} // have access to your final data here. 
            );
    }
}

Things to know:

  1. You can remove the subscribe() execution and use the async pipe in your template;

  2. The use of the operator map in pipe() is optional, you can handler your final data directly from your first callback subscribe().

  3. You can convert your Observable to Promise using toPromise() method in one observable. Don't forgot async / await in your ngAfterViewInit.

Let me know if there is something I can help.

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

2 Comments

Hi @Mathias, Thanks for your help, I did what you suggested and end up with an error that I am trying to figure out. The error say "Uncaught (in promise) undefined"
Can you put your code in a codesandbox for me? This way I can have the big picture of the problem. codesandbox.io/s
0

Try:

Object.keys(this.jobs).forEach(job => {
    console.log(this.jobs[job]);
});

4 Comments

Thanks, but the result is the same.
@WatiYé is this by any chance still an Observable? Did you remember to subscribe? Can we see the getJobs() function in the JobsService Please?
Happy I could help :)
it's actually not the problem. I tried synchronous http request and it worked fine that's why I thought you were right. I just add the content of my service I hope it can help you to help me :D
0

Try to assign an iterator function with below part replacement by this code:

// Nothing happened when looping through the array
this.jobs.forEach(oneJob, function(value, key) {
    console.log(key + ': ' + value);
});

Usage of forEach in AngularJS:

For documentation try to check AngularJS forEach Docs

Syntax:

someIterable.forEach(object, iterator, [context])

1 Comment

Thanks @furkanayd, the problem is not the iteration.
0

Please check below example

class Job {
    id: any;
    status: any;
    constructor(obj: any) {
        this.id = obj.id;
        this.status = obj.status;
    }
}

let arr = [
    {
        id: 1,
        status: "job"
    }, {
        id: 2,
        status: "job2"
    }
];

let newArr: any = [];

arr.forEach(a => {
    let obj: Job = new Job(a);
    newArr.push(obj);
})

console.log(newArr);

newArr.forEach((a: any) => {
    console.log(a);
})

5 Comments

Thanks. I tried a lot of different way to loop already, I think the problem is not the looping.
I have changed my commit please check and tell me it's working or not
The part you remove will break my code the Job model will create the object in the way that will be handle by the template. My problem is that the array of object (Job) got populated and display fine in the template but when I come to ngAfterViewInit, that array looks empty.
I have created a sample code for your problem please take a look and let me know the status... link:- cutt.ly/ce8jHwX you can view the console log for status
Thanks @chirag, but I think that part already work I don't know why but the jobs show up in my template fine. The only problem that I trying to understand is why when I come back to ngAfterViewInit, that array some how become empty.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.