Blade component does not dispatch change events

I want to create a simple blade component for a people counter. I have to use it multiple times in my Livewre component, and call it with <x-person-counter wire:model="number_adults" />, <x-person-counter wire:model="number_children" />

My blade component looks like this:

<div x-data="{ counter: 0 }"
    @change="$dispatch('input', $event.target.value)">
    <input {{ $attributes }} x-ref="input" type="hidden" x-model="counter" />
    <div>
        <button
            type="button"
            @click="counter -= 1"
            class=""
        >-</button>
        <div x-text="counter"></div>
        <button
            type="button"
            @click="counter += 1"
        >+</button>
    </div>
</div>

Inside the component everything works well, but my wire:model field is not updated.

Any help would be appreciated.
Thanks!

have you recalled your counter after the event was fired?

for example in your component

// ....
public $counter;

public function increase()
{
    $this->counter = $this->counter + 1;
    $this->counter
}

public function decrease()
{
    $this->counter = $this->counter - 1;
    $this->counter
}

by the way in this example that you provide, it’s work very well, just make sure you are placing the @livewireScripts in the footer to try to clear you browser cache

The counter is handled in AlipneJs inside the component, and shoud dispatch that change up to the Livewire, but it doesn’t.

can you give us a full code?

Hey @hmihail,

the problem is, that there is no change or input event dispatched by the input field when the value is changed through x-model. You can try it yourself by simply adding a console.log to your @change handler.

You could for example dispatch the input event from within the button click, with the updated counter value.

Hope this solves your problem!

I have the dispatch event on the outer div, like in the example by Caleb on the screen cast, but somehow I missed something because mine isn’t working.

Can you show us how your code now looks like?

Here is the entire component:

<div x-data="init()"
    @change="$dispatch('input', $event.target.value)">
    <input {{ $attributes }} x-ref="input" type="hidden" x-model="counter" />
    <div class="flex justify-between bg-gray-100 border-0">
        <button
            type="button"
            @click="increment(-1)"
            class=""
        >-</button>
        <div
            x-text="counter"
            class=""
        >
        </div>
        <button
            type="button"
            @click="increment(1)"
            class=""
        >+</button>
    </div>
</div>

<script>
    function init() {
        return {
            counter: 0,
            increment(step) { 
                this.counter += step;
                if(this.counter < 0)
                    this.counter = 0;
                this.$refs.input.value = this.counter;
            },
        }
    }
</script>

I need to revisit the Screencast, but the problem still is, that there shouldn’t be a “change” Event emitted.
So your input event will never fire.

Try to dispatch your input event at the end of your “increment” method.

I don’t know how to do that, I am a beginner. I tried the dispatch there but I get a JS error.

Hey @hmihail,

i’ve edited your code, to show you how:

<div x-data="init()"
    <input {{ $attributes }} x-ref="input" type="hidden" x-model="counter" />
    <div class="flex justify-between bg-gray-100 border-0">
        <button
            type="button"
            @click="increment($dispatch, -1)"
            class=""
        >-</button>
        <div
            x-text="counter"
            class=""
        >
        </div>
        <button
            type="button"
            @click="increment($dispatch, 1)"
            class=""
        >+</button>
    </div>
</div>

<script>
    function init() {
        return {
            counter: 0,
            increment($dispatch, step) { 
                this.counter += step;
                if(this.counter < 0)
                    this.counter = 0;
                this.$refs.input.value = this.counter;
                $dispatch('input', this.counter);
            },
        }
    }

Probably you got the JS Error, because you need to pass the $dispatch method as a parameter when you want to use it in a function.