0

My problem is that in setStyle() function, I have the right values for those 2 arrays, but it won't enter on .map. Why is that? Where should I call setStyle() function in order to trigger .map, if not in ngOnInit?

  ngOnInit() {
      this.existingCustomers = this.trackService.refreshExCusts()
      this.nonExistingCustomers = this.trackService.refreshNonExCusts()
      this.setStyle()
  }

  setStyle() {
    // it enters here
    console.log(this.existingCustomers) // has the right value
    console.log(this.nonExistingCustomers) // has the right value

    this.existingCustomers.map((val) => this.lineStyle.push({ // won't enter here
        "customer": val.customer_name,
        "color": '#000000'
    }))

    this.nonExistingCustomers.map((val) =>  this.lineStyle.push({ // won't enter here
      "customer": val.customer_name,
      "color": '#ff0000'
    }))

    console.log(this.lineStyle) // this is empty
  }

The value of the arrays:

existingCustomers = [{customer_name: "a"}, {customer_name: "b"}]

nonExistingCustomers = [{customer_name: "c"}, {customer_name: "d"}]

Thank you for your time!

Tenzolinho
  • 922
  • 2
  • 15
  • 35
  • 2
    Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Igor Jan 16 '19 at 15:44
  • I am thinking that `trackService.refreshExCusts` and the other method as well are asynchronous (return observable or promise) so you have to await the results. Also `map` returns a new altered array which you have to assign to something. – Igor Jan 16 '19 at 15:45
  • 2
    If `existingCustomers` is an array you're probably looking for `foreach` instead of `map`. – frido Jan 16 '19 at 15:47
  • Is there an error? – Aragorn Jan 16 '19 at 15:52
  • No error, just an empty array (`this.lineStyle = []`) – Tenzolinho Jan 16 '19 at 15:53
  • Please add a console.log of `this.lineStyle` to the bottom of the setStyle method. Is the correct value present or not? – CaKa Jan 16 '19 at 15:55
  • No, it's empty. – Tenzolinho Jan 16 '19 at 15:56
  • @Igor I did as you said and I `await`ed the response, and now I have the right values. I set a timeout of 3 seconds. But how much do I need to wait? How do I know? Why 3, why not 1, or 10 seconds? I don't want to wait much longer that needed. – Tenzolinho Jan 16 '19 at 15:57
  • Where are you printing `this.lineStyle` to find out it is empty? My suspect is that `map` and `forEach` take call back functions, so there might be the race condition. Try the `for` loop. – Aragorn Jan 16 '19 at 16:01
  • @Tenzolinho You have to provide more details. What does `this.trackService.refreshExCusts()` and `this.trackService.refreshNonExCusts()` return and look like? What type is `this.existingCustomers` and `this.nonExistingCustomers`? – frido Jan 16 '19 at 16:01
  • You should try to enter in debug mode to really see if your arrays are filled when entering the setStyle() method. I suspect that the logs are printed after the promises resolves, but that the `.map` executes before the promises are resolved (which results in your error case) – Kapcash Jan 16 '19 at 16:04
  • 1
    Awaiting the result from a promise should not be done by setting a timeout. Read over the suggested duplicate, it is rich in information and should help you better understand how to work with asynchronous callbacks in javascript / typescript. – Igor Jan 16 '19 at 16:04
  • 1
    To add to @Igor: do NOT use `setTimeout()` or whatever you're using. You cannot guarantee that after the timeout is done, the value will be there. Also, you're not operating at maximum speed; you absolutely need to either `subscribe` to the functions, if they're `Observable`s, or use something like `forkJoin(method1, method2).subscribe((ex, nex) => { this.existingCustomers = ex; this.nonExistingCustomers = nex; this.setStyle() }`. – Jeff Huijsmans Jan 16 '19 at 16:13
  • 1
    I think it would help everyone if you posted the code for TrackService. – Wilhelmina Lohan Jan 16 '19 at 16:54

2 Answers2

1

The object arrays are defined incorrectly, they should look like below for your code to work:

  existingCustomers = [{ customer_name: "a" }, { customer_name: "b" }];

  nonExistingCustomers = [{ customer_name: "c" }, { customer_name: "d" }];

I tested with these arrays, and I get the lineStyle printed in console as:

[{"customer":"a","color":"#000000"},{"customer":"b","color":"#000000"},{"customer":"c","color":"#ff0000"},{"customer":"d","color":"#ff0000"}]

UPDATE: OP Confirmed that the Array definition was typo in the question. So my only other suspect is how the map or forEach take a callback function and therefore race condition when console.log prints the array. Try the for loops:

  setStyle() {
    // it enters here
    console.log(this.existingCustomers) // has the right value
    console.log(this.nonExistingCustomers) // has the right value

    for (let i = 0; i < this.existingCustomers.length; i++) {
      this.lineStyle.push({ // won't enter here
        "customer": this.existingCustomers[i].customer_name,
        "color": '#000000'
      })
    }

    for (let i = 0; i < this.nonExistingCustomers.length; i++) {
      this.lineStyle.push({ // won't enter here
        "customer": this.nonExistingCustomers[i].customer_name,
        "color": '#ff0000'
      })
    }

    console.log(JSON.stringify(this.lineStyle)) // this is empty
  }
Aragorn
  • 5,021
  • 5
  • 26
  • 37
  • I am very sorry, I did a mistake when I wrote the value of those 2 arrays.. they are build like you said.. :( the problem is with the callback for sure – Tenzolinho Jan 16 '19 at 16:39
-1

Make sure that you are implementing onInit:

import { OnInit } from '@angular/core';
export class Random implements OnInit {
  constructor() { }

  // implement OnInit's `ngOnInit` method
  ngOnInit() { 
     console.log(`OnInit`); 
  }

}
  • 1
    This is not required, as interfaces are a typescript construct they will disappear during compilation. Angular will always call `ngOnInit` if the method is defined, regardless of whether or not the interface was implemented in the source. https://angular.io/guide/lifecycle-hooks#interfaces-are-optional-technically – UncleDave Jan 16 '19 at 16:15
  • Good practice though – Wilhelmina Lohan Jan 16 '19 at 16:54