1

I'm pretty newbie in angular and I hope someone can help me >.<

I have a component which has an object array as property. The thing is that when I update that array with a new object all the items in array became the last object that I have pushed

this is the component im trying to update:

export class DisplayComponent {
  weather: Weather = {
    city: null,
    conditions: null,
    temperature: null,
    icon: null,
    humidity: null
  }
  history: Array<Weather> = []

  update(weather: Weather) { 
    this.weather = weather
    console.log(weather)
    this.history.push(weather)
    console.log(this.history)
  }
}

This is what console logs returns after trying to insert the first object:

Weather {city: "Granada", conditions: "Clouds", temperature: 25.38, icon: "http://openweathermap.org/img/wn/02d@2x.png", humidity: 83}
0: Weather {city: "Granada", conditions: "Clouds", temperature: 25.38, icon: "http://openweathermap.org/img/wn/02d@2x.png", humidity: 83}

But when i try to add another one I get this:

Weather {city: "Barcelona", conditions: "Clouds", temperature: 13.89, icon: "http://openweathermap.org/img/wn/02d@2x.png", humidity: 54}

0: Weather {city: "Barcelona", conditions: "Clouds", temperature: 13.89, icon: "http://openweathermap.org/img/wn/02d@2x.png", humidity: 54}
1: Weather {city: "Barcelona", conditions: "Clouds", temperature: 13.89, icon: "http://openweathermap.org/img/wn/02d@2x.png", humidity: 54}

As you can see what i have now is "barcelona" two times when granada was the first one.

Edit:

This is the function that submit the object:

  submit() {
    this.weatherData.load(this.city).subscribe(data => {
      this.weather.city = data['name']
      this.weather.conditions = data['weather'][0]['main']
      this.weather.temperature = data['main']['temp']
      this.weather.icon = this.weatherData.getIconUrl(data['weather'][0]['icon'])
      this.weather.humidity = data['main']['humidity']
      this.onSelection.emit(this.weather)
    })

Coud someone help me with this? thanks in advance!!

AngelQuesada
  • 387
  • 4
  • 19

2 Answers2

1

It happens because objects are reference types. You need to create brand new object and then push it:

update(weather: Weather) { 
    this.weather = JSON.parse(JSON.stringify(weather))
    console.log(weather)
    this.history.push(weather)
    console.log(this.history)
  }

However, in case of your data has Date, functions, undefined, or Infinity within your object there are other ways. E.g.:

createWeatherObject(weather) {
    return {
       weather.city,
       weather.conditions,
       weather.temperature,
       weather.icon,
       weather.humidity
   }
}

update(weather: Weather) { 
    this.weather = this.createWeatherObject(weather);
    console.log(weather)
    this.history.push(weather)
    console.log(this.history)
  }
StepUp
  • 36,391
  • 15
  • 88
  • 148
  • this shouldn't be needed. (also `{...weather}` is better if this was needed) something else is happening – bryan60 Nov 21 '19 at 14:10
  • 1
    This worked for me, the sad thing is that I dont understand why. I think that i need to study basic javascript things like what you explained at the begin. Thank you so much. – AngelQuesada Nov 21 '19 at 15:41
  • 1
    @AngelQuesada it is okay, Just read this [article](https://medium.com/dailyjs/back-to-roots-javascript-value-vs-reference-8fb69d587a18) and this [article](https://stackoverflow.com/questions/6605640/javascript-by-reference-vs-by-value) – StepUp Nov 21 '19 at 15:47
1

So there is nothing inherently wrong with this code you have here, your bug is elsewhere in your app, likely before or how you're calling the update method, blitz: https://stackblitz.com/edit/angular-7-master-c7tg5q?file=src/app/app.component.ts

What might be happening: objects and arrays in javascript are stored by reference, which means, if you stick an object in an array, all you've stuck in the array is a reference to that object. and if you change that object, it changes everywhere you've stored that reference. This is likely what's going wrong in your app, but not in the code you have here.

EDIT after more updates:

so yea, the problem is that you're mutating the weather object in the submit function... do this instead:

this.weatherData.load(this.city).subscribe(data => {
  // create a new object, don't mutate the old one
  const weather = {
    city: data['name'],
    conditions: data['weather'][0]['main'],
    temperature: data['main']['temp'],
    icon: this.weatherData.getIconUrl(data['weather'][0]['icon']),
    humidity: data['main']['humidity']
  }
  this.weather = weather // is this required since you do it in the update() method?
  this.onSelection.emit(this.weather)
})

general rule of thumb: avoid object / array mutation whenever possible, it leads to weird bugs like this.

bryan60
  • 28,215
  • 4
  • 48
  • 65