Cameron Hurd Cameron Hurd - 4 months ago 7
Javascript Question

Why isn't my custom setter invoked when I create a typed array of objects?

http://plnkr.co/edit/TNdkfmoCc9JA1G7cEk26?p=preview

I've created a class,

Item
, which has custom
get date(): Date
and
set date(date: Date)
methods:

export class Item {
id: number;
name: string;
_date: Date;

get date(): Date {
return this._date;
}

set date(date: Date) {
this._date = date;
this.name = (this.name + ' (updated)');
}
}


In my app component, I try three things to invoke my custom setter. I thought they would all work, but only one does, and I'd like some help to understand why!


  1. Pass an array of objects matching the
    Item
    class definition to the field typed as
    Item[]
    .

  2. I manually set
    date
    on one the objects (an
    Item
    ) in the
    items
    property. The date is set, but not via my setter. (Indicated by the
    name
    property remaining unchanged.)

  3. I instantiate my own
    Item
    , set the
    date
    , and push it to
    items
    . This method works!



I tried being a more specific by moving properties to a constructor, guessing that maybe the object's contents were passed there when I give a typed field my array of objects. (I made a fork of my plunker with this attempt.)

Why isn't my setter invoked when I create an array of objects bearing the class with that method?

import {Component, OnInit} from '@angular/core'
import {Item} from './item'

@Component({
selector: 'my-app',
providers: [],
template: `
<div>
<h2>{{name}}</h2>
<div *ngFor="let item of items">
{{ item.name }} &mdash; {{ item.date | date:"d/M/y h:mm a" }}
</div>
</div>
`,
directives: []
})
export class App implements OnInit {

items: Item[];

constructor() {
this.name = 'Understanding Getters/Setters in Typescript'
}

ngOnInit() {
this.items = [{
id: 1,
name: 'Item 1',
date: new Date()
}, {
id: 2,
name: 'Item 2',
date: new Date(2016, 0, 2, 21)
}];

// Doesn't trigger the setter
this.items[1].date = new Date(1985, 0);

let testItem = new Item();
testItem.name = 'Item 3';
// Triggers the setter
testItem.date = new Date(2001, 0, 1, 6);

this.items.push(testItem);
}
}

Answer

This is an array/object literal:

[{
  id: 1,
  name: 'Item 1',
  date: new Date()
}, {
  id: 2,
  name: 'Item 2',
  date: new Date(2016, 0, 2, 21)
}];

It's going to overwrite the Item[] array you initialized items with in the declaration. Each of those array elements is just a plain object, not an instance of your Item class. For that you would need to use new Item():

this.items = [ new Item(), new Item() ];
this.items[1].date = new Date(1985, 0);

As for this:

let testItem = new Item();
testItem.name = 'Item 3';
// Triggers the setter
testItem.date = new Date(2001, 0, 1, 6);

It works because you are creating a new instance of your class. And thus testItem.date will be your setter