eskimo
eskimo

Reputation: 2625

Using AlpineJS (3) magic properties in javascript function

I'm using a store for a modal and like to use the magic $watch method like so:

Alpine.store('modal', {
    init() {
        this.$watch('this.open', (val) => console.log(val))
        // Here I like to do if(open) { document.body.classList.add('overflow-hidden') } 
    },
    open: false,
    id: null,
    close() {
        this.open = false
        this.id = null
    }
})

But I get TypeError: this.$watch is not a function

Upvotes: 4

Views: 2351

Answers (2)

Shashank Bhatt
Shashank Bhatt

Reputation: 857

You can't use the $watch in the Alpine.store, still you have two options available

  1. Copying store's data way

Use Store's data as x-data of html element and watch for that data using $watch in html itself. So here mystore's data will be the x-data itself so watching it will eventually watch store's isStoreOpen property of that store.

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
<script>
 Alpine.store('mystore',{
    init() {
      console.log('hi there in store')

    },
    isStoreOpen: true,
    toggle() {
        
          this.isStoreOpen = !this.isStoreOpen;
    }
 })
</script>

<div x-data="$store.mystore" x-init="$watch('isStoreOpen', (val) => console.log(val))">
  <p>
    What you can toggle
  </p>
  <button @click="toggle()" x-text="$store.mystore.isStoreOpen">
    
  </button>
</div>

  1. Parameters passing way.

Or for some reason if you need to use magic things in store's method itself or have different x-data then you have to pass magic things using parameters. Here i took startStoreWatch method in init method of data instead of init method of store as the store's init method is used to init that store.

This way store will watch it's own property same as the data watches it's own.

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
<script>
 Alpine.store('mystore',{
    init() {
      console.log('hi there in store')
            
    },
    count: 0,
    startStoreWatch($watch, $store) {
     $watch('$store.mystore.count', (val) => console.log(val))
    },
    toggle() {
       this.count++;
    }
 })
</script>

<div x-data="{
      init() {
         // here we are watching isOpen of data and count of store
         this.$store.mystore.startStoreWatch(this.$watch, this.$store)
         this.$watch('isOpen', (val) => console.log(val))
      },
      isOpen: false,
      toggle() {
        this.isOpen = !this.isOpen;
      }
}">
  <p x-show="isOpen">
    What you can toggle
  </p>
  <button @click="() => {
    toggle()
    $store.mystore.toggle()
  }" x-text="`store is toggled ${$store.mystore.count} times`">
    
  </button>
</div>

Upvotes: 0

kylepg
kylepg

Reputation: 155

Wrap the second argument in an arrow function:

Alpine.store('modal', () => ({
    init() {
        this.$watch('this.open', (val) => console.log(val))
    },
    open: false,
    id: null,
    close() {
        this.open = false
        this.id = null
    }
}))

Arrow functions capture the this value of the enclosing context, thus giving you access to Alpine's magic methods.

Upvotes: 2

Related Questions