4

I share array of objects to my components trough service. So in one moment I want to replace one of the array object's properties with the properties of new object(I replace the object). So my shared object should update in all templates where it is used.

https://plnkr.co/edit/0sRxSivEaEPLsNAJo7MV?p=preview

// my.component.ts
@Component({ 
selector: 'my-component',
template: '<div>MyComponent: {{item.name}}</div>',
})
export class MyComponent implements OnInit {
  constructor(private myService: MyService) {}

  private item = myService.myListData[0];

  ngOnInit() {
    // 1. - This triggers change detection in app.ts template
    this.item.name = 'Name 1111';

    setTimeout(() => {
      // 2. - This doesn't trigger change detection in app.ts template
      let newObj = {name: 'Name 222', age: 225};
      this.item = newObj;
    }, 3000);
  }
}

In my case //1 change template value in app.ts and my.component.ts but //2 trigger change only in my.component.ts

I'm wondering why //2 is doesn't update app.ts template and is there a way to do it without looping trough object properties?

Update: I managed to solve my issue by using Object.assign(). There is no change detection when replacing objects.

setTimeout(() => {
  // 2. - This doesn't trigger change detection in app.ts template
  let newObj = {name: 'Name 222', age: 225};
  Object.assign( this.item , newObj);
}, 3000);
Свободен Роб
  • 2,579
  • 2
  • 20
  • 26
  • 3
    Quite a lot of captions but almost no context. Please post the components class, including the `@Component()` decorator and the template of the component and explain the actual behavior and expected behavior. – Günter Zöchbauer Jan 18 '17 at 08:14
  • Ok, I think now it is ok. Thank you – Свободен Роб Jan 18 '17 at 08:29
  • 1
    There is still no HTML. `let` before `let item` is redundant or even invalid (not a TS pro). I think this variable assignments code should be inside a method. Doesn't make sense the way you have it. – Günter Zöchbauer Jan 18 '17 at 08:32
  • Sorry for that. No HTML is needed. – Свободен Роб Jan 18 '17 at 08:35
  • 1
    I think it is. Change detection happens all the time, no matter if you change something or not. What you're probably talking about is whether change detection should detect a change and update the view. For that we need to see your view (HTML) and your explanation what the actual and expected behavior is. – Günter Zöchbauer Jan 18 '17 at 08:37
  • Pls add a small demo – yurzui Jan 18 '17 at 08:43
  • Here is a demo :) https://plnkr.co/edit/0sRxSivEaEPLsNAJo7MV?p=preview – Свободен Роб Jan 18 '17 at 09:38
  • 2
    What you seem to expect doesn't have anything to do with change detection. If you assign a new (different) object to `this.item` then there is no connection between `AppComponent` and `MyComponent` anymore. Why do you expect anything to update in `AppComponent`? – Günter Zöchbauer Jan 18 '17 at 12:25
  • Because you changed the reference of your item in the my.component, app.component doesn't track the item. my.component is now tracking changes of newly created component. – omeralper Jan 18 '17 at 13:24
  • The above plnkr example seems to be working without Object.assign(). So whats the right way for change detection to happen? – Ajey Mar 17 '17 at 05:46

2 Answers2

3

I know this is a bit of an old question, but I was running into an issue where change detection wasn't running "correctly", or at least when I anticipated it would.

In my case, assigning a variable I was watching, we'll call it oldValue, wasn't triggering the change detection. This was how I had it originally:

// INCORRECT APPROACH
oldValue = newValue

As noted in the Updated... portion of the OP's question, a good solution is to use Object.assign():

// CORRECT APPROACH
Object.assign(oldValue, newValue)

In this case (in my experience), change detection would get run on oldValue.

Cheers!

kbpontius
  • 3,867
  • 1
  • 30
  • 34
0

I think the OP is wanting to bind several views to the same service data. Here is a plunker (modified poster's original) showing how it can be done. Basically bind the views to the same service member and not to the component's individual members. So that the changes reflects automatically in all the similar bindings.

https://plnkr.co/edit/PNQmLarmP3g7j7f42cXD?p=preview

@Component({ 
    selector: 'my-component',
    template: '<div>MyComponent: {{myService.Item.name}}</div>',
})
export class MyComponent implements OnInit {
   constructor(private myService: MyService) {}

   private item = myService.myListData[0];

   ngOnInit() {
     // 1. - This triggers change detection
     this.item.name = 'Name 1111'
     this.myService.Item = this.item;

     setTimeout(() => {
       // 2. - This doesn't trigger change detection in app.ts template
       let newObj = {name: 'Name 222', age: 225};
       this.myService.Item = newObj;
     }, 3000);
   }
}

On this topic, I always wondered if there is a way to achieve the same and create a reference to a service member like a short-hand to be used in the component HTML.

Item = Alias of MyService.Item ;

and the HTML would simply bind to

{{Item}}
Meryan
  • 1,285
  • 12
  • 25