2

As I was going through the "Tour of Heroes" Angular 2 tutorial, I have noticed that when ngModel changes, the change propagates to other components utilizing the same object. But when I tried to log the mock service constant HEROES on the console, its value also changed.

mock-heroes.ts

import { Hero } from './shared/hero.model';

export const HEROES: Hero[] = [
  { id: 11, name: 'Mr. Nice' },
  { id: 12, name: 'Narco' },
  { id: 13, name: 'Bombasto' },
  { id: 14, name: 'Celeritas' },
  { id: 15, name: 'Magneta' },
  { id: 16, name: 'RubberMan' },
];

hero.service.ts

import { Injectable } from '@angular/core';
import { Hero } from './hero.model';
import { HEROES } from '../mock-heroes';

@Injectable()
export class HeroService {
  getHeroes(): Promise<Hero[]> {
    console.log(HEROES); // print the constant HEROES value
    return Promise.resolve(HEROES);
  }
}

hero-detail.component.html

<div *ngIf="hero">
  <h2>{{hero.name}} details!</h2>
  <div><label>id: </label>{{hero.id}}</div>
  <div>
    <label>name: </label>
    <input [(ngModel)]="hero.name" placeholder="name"/>
  </div>
</div>

heroes.component.html

<h3>My Heroes</h3>
<ul class="heroes">
  <li *ngFor="let hero of heroes" (click)="onSelect(hero)" [class.selected]="hero === selectedHero">
    <span class="badge">{{hero.id}}</span> {{hero.name}}
  </li>
</ul>
<hero-detail [hero]="selectedHero"></hero-detail>

heroes.component.ts

import { Component, OnInit } from '@angular/core';
import { Hero } from './shared/hero.model';
import { HeroService } from './shared/hero.service';

@Component({
  selector: 'my-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
  heroes: Hero[];
  selectedHero: Hero;

  constructor(private heroService: HeroService) { }

  ngOnInit(): void {
    this.getHeroes();
  }

  getHeroes(): void {
    this.heroService.getHeroes()
      .then(heroes => this.heroes = heroes);
  }

  onSelect(hero: Hero): void {
    this.selectedHero = hero;
  }
}

The HeroService is injected from the AppModule providers array (global service provider).

Changing the name from "Narco" to "Narcosssss" through the input:

enter image description here

updates the constant HEROES as seen on the console:

enter image description here

Can someone please explain to me how it works?

eko
  • 39,722
  • 10
  • 72
  • 98
Rax Weber
  • 3,730
  • 19
  • 30

1 Answers1

4

Your hero objects have the same reference throughout your app. So, if you change the referenced object. The property will change wherever it's been referenced.

eko
  • 39,722
  • 10
  • 72
  • 98
  • So `HEROES` constant is also referenced? Knowing that `HEROES` is only accessible through a service, I do not see which part of the code does the referencing of it. That really gives me a confusion. – Rax Weber Mar 29 '17 at 07:16
  • 1
    You are using `getHeroes` method to get the `HEROES`; it is not giving you a new object it is giving you "that" object. And then you assign `this.heroes = heroes`, `heroes` is "that" object and you are passing "that" objects reference to `this.heroes`. – eko Mar 29 '17 at 07:21
  • Thanks to you, I've just learned that in JS, when a variable is referring to an object (which includes an array) and you change its property, the referenced object's property is also changed. I didn't really know this until now because I haven't encountered any situation where this concept is applied. :) – Rax Weber Mar 29 '17 at 07:37
  • @RaxWeber Glad I could help :-) – eko Mar 29 '17 at 07:39