Ember Octane, Tracked property not rerendering template

935 Views Asked by At

Coming from a React background, I'm having issues understanding EmberJs "Tracked" concept. On paper it shouldn't be different from "React state".

So what I have understood is that when we anotate a property with @tracked it should cause a re render when there is a change in this property.

Please take a look at the code below:

ProductItemComponent

import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';

export default class ProductItemIndexComponent extends Component {
  @service('cart') cartService;

  @tracked addedToCart = false;

  @action
  checkItemInCart(id) {
    if (this.cartService.items.findBy('id', id)) {
      this.addedToCart = true;
    } else {
      this.addedToCart = false;
    }
  }
}

Template,

<div class="card-container">
  <div class="card product-item" {{did-insert (fn this.checkItemInCart @item.id)}}>
    <img src={{@item.image}} class="product-image card-img-top" alt="...">
    <div class="card-body">
      <h5>{{@item.title}}</h5>
    </div>
    <div class="footer">
      <p class="card-text"><span class="badge badge-secondary"><strong>Price: </strong>{{@item.price}}</span></p>
      <button type="button" class="btn btn-warning" {{on 'click' (fn @handleCartAction item)}}
        disabled={{this.addedToCart}}>Add
        to cart</button>
    </div>
  </div>
</div>

When I first render the component I'm checking if the current item is present in the cart using {{did-insert (fn this.checkItemInCart @item.id)}} and if its present I'm switch the tracked property @tracked addedToCart = false; to true else false.

In theory, this should disable my button in my productItem template as soon as it finds the Item in the cartService. It only works when I go to another page and then come back.

But there is no rerender of the page. Can someone help me understand what I might be doing wrong?

Thank you in advance

1

There are 1 best solutions below

2
On BEST ANSWER

Your problem is that checkItemInCart is called only once, so addedToCart is not updated once cartService.items were changed.

I think proper solution would be to make addedToCart depends on cartService.items and item

get addedToCart(){
  return !!this.cartService.items.findBy('id', this.args.item.id)
}

For this to work cartService.items should also be tracked property, and be updated with methods like pushObject, see Why won't my tracked array update in Ember Octane?