4

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

4
  • Is there a specific reason why you are not using Alpine's build in way to bind classes? (alpinejs.dev/directives/bind#class-object-syntax) In this case, you could add x-data :class="{ 'overflow-hidden': $store.modal.open }" to your body element. Commented Sep 6, 2021 at 8:28
  • Yeah is because I extracted the code into a JS file that I can reuse. And in that JS file I want to watch the open value so that I can add a class to the body. I don't want to add an x-data on the body. Commented Sep 8, 2021 at 18:48
  • 1
    Did you find a solution to this? Commented Jan 26, 2022 at 13:37
  • No I actually didn't. What you could try is to add a function that you always use to open the modal, like: open() { this.open = true; document.body.classList.add('overflow-hidden') }. I never tried this in an external component. Not sure if the document object works like this here. Commented Jan 27, 2022 at 20:15

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.