5

I have an hero array that I show it in list by *ngFor and when I Click on one of it element it copied on new variable and new variable go to input by tow way binding . my heroClass:

export class Hero {
    id: number;
    name: string;
  } 

my hero-mock list:

import { Hero } from './heroClass';

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' },
  { id: 17, name: 'Dynama' },
  { id: 18, name: 'Dr IQ' },
  { id: 19, name: 'Magma' },
  { id: 20, name: 'Tornado' }
];

My hero component:

   import { Component, OnInit } from '@angular/core';
    import { Hero } from '../hero';
    import { HEROES } from '../mock-heroes';

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

      heroes = HEROES;

      selectedHero: Hero;


      constructor() { }

      ngOnInit() {
      }

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

heroes.component.html

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

<div *ngIf="selectedHero">

  <h2>{{ selectedHero.name | uppercase }} Details</h2>
  <div><span>id: </span>{{selectedHero.id}}</div>
  <div>
    <label>name:
      <input [(ngModel)]="selectedHero.name" placeholder="name">
    </label>
  </div>

</div>

the problem is when i select one hero and show copy of it on text input and change it the hero of list that is selected changing too.

in angularjs 1 I prevent from this issue by using angular.copy() built in method but in angular 2 i have to create new of Hero and attributing propery of selectedHero to main hero:

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

is there other way to deep copy in angular 2 without using jquery or js function and above way?

Aref Zamani
  • 2,023
  • 2
  • 20
  • 40
  • i don't want use js functions – Aref Zamani Dec 17 '17 at 07:23
  • 1
    The same way as in any other JS application. It isn't the responsibility of the framework to provide general helper functions. The fact AngularJS tried to emulate jQuery API and provided `copy` and `extend` shouldn't be taken into account and means that something went wrong there. – Estus Flask Dec 17 '17 at 07:36
  • 1
    You are using a JavaScript framework and you do not want to use JavaScript functions? What? – Lazar Ljubenović Dec 17 '17 at 07:39
  • This is angular - not angularJS @estus – Zze Dec 17 '17 at 07:53
  • 1
    @LazarLjubenović angularJS is a javascript framework - angular is typescript... Yes it compiles to javascript and I get that, however searching for a typescript specific answer is acceptable. – Zze Dec 17 '17 at 07:54
  • @Zze The OP mentions AngularJS as an example where deep copy was provided by the framework. It wasn't me who added angularjs tag since it wasn't really relevant. – Estus Flask Dec 17 '17 at 07:59

2 Answers2

13

This is pretty hacky in my opinion, but it does work.

this.selectedHero = JSON.parse(JSON.stringify(hero));

For Shallow Copy: You can use the spread operator:

this.selectedHero = {...hero};
let {...example} = hero;
Zze
  • 18,229
  • 13
  • 85
  • 118
  • The spread operator will do a shallow copy, which might not be what the developer wants. The JSON trick will mess with things like Dates and other complex objects, including circular references. – Lazar Ljubenović Jun 29 '19 at 10:03
5

Use lodash's cloneDeep function.


There's nothing in Angular for deep cloning an object because it is not Angular's concern to provide such a function.

Lazar Ljubenović
  • 18,976
  • 10
  • 56
  • 91