AlpineJS unexpected assignment behaviour?
# help-with-other
d
Any AlpineJS heros out there? I'm encountering some strange behaviour. I have a list of items that may be marked as favourite. Sometimes these lists are rendered using razor, sometimes lists are generated with a parent AlpineJS component with
x-for
. In the former case, I assign the item id to a data attribute
data-favourite-id="1"
. In the latter case, I would like to inherit the item id from the parent "item" component. What I'm running into is that my state is unintentionally shared across all components. Here is a sample of my favourites code:
Copy code
typescript
alpine.data('favourites', () => ({
  favouriteId: undefined,
  init() {
    // Favourite may be inherited from parent app (overview card for example)
    if (!this.favouriteId) {
      const favouriteId = this.$el.dataset['favouriteId'];
      if (!favouriteId) return;
      this.favouriteId = favouriteId;
    }
  }
}));
If I have a razor card like this:
Copy code
html
<article>
    <button x-data="favourites" data-favourite-id="1">Mark favourite</button>
</article>
Then the snippet works. But if I have a card like this:
Copy code
html
<template x-for="article in articles">
<article x-data="overviewCard"> <!-- notice the x-date here -->
    <button x-data="favourites">Mark favourite</button>
</article>
</template>
And I do this:
Copy code
typescript
alpine.data('overviewCard', () => ({
  init() {
    this.favouriteId = this.article.id;
  }
}));
Then the favouriteId is still overwritten with
undefined
in the favourite component. However, if I remove
favouriteId: undefined
from the favourites component, every favourite button suddenly uses the same ID value. Does anybody know what is going on here and where I'm going wrong?
It appears that if you add a new field to your state through the init function, then the field value will be added to the top most state object. So if you have a single overarching state, then the field will be added to that instead of the closest state object. A way to workaround this is to create a new state object that specifically sets the field values that you will need to act as a "barrier" so that the field values cannot accidentally bubble up to a higher level state object.
So like this:
Copy code
- topLevelData
  - barrrierData (includes fields set to 'undefined')
    - favouriteData (sets a value for the field)
4 Views