List recursive with checkbox component data into parent component update values - laravel

Help to list recursive with checkbox component data into parent component update values:
Parent File:
<TreeVue :items="props.allModules" :selectedItems="userForm.userModules"/>
TreeVue File:
<template>
<div v-for="item in items" :key="item.name" class="overflow-hidden rounded-lg bg-gray-50">
<div class="px-4 py-5 sm:p-6" >
<div class="flex items-center ">
<input :id="item.id" type="checkbox" :value="item.id" v-model="props.selectedItems" class="w-6 h-6 text-blue-600 bg-gray-100 rounded border-gray-300 focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
<label for="default-checkbox" class="ml-2 text-sm font-medium text-gray-900 dark:text-gray-300">{{ item.name }}</label>
</div>
<div v-if="item.children" class="ml-5">
<Tree :items="item.children" :selectedItems="selectedItems" />
</div>
</div>
</div>
</template>
<script setup>
import { defineProps } from "vue";
const props = defineProps({
items: Object,
selectedItems: Object,
});
</script>
ConsoleLog:
app.js:7839 [Vue warn] Set operation on key "selectedItems" failed: target is readonly. Proxy {items: Proxy, selectedItems: Proxy}
I need to update parent value after selected item on child TreeVue.
I read something about Emit, but I don't know how to implement it, because I'm new to Vue.

Related

Multiple reusable modals vue 3 - how to keep track of paging? be more in control of modal functions

I'm trying to create a reusable modal in Vue 3 using the composition API. I'm finding it difficult due to a lack of knowledge to keep track of the modals that are shown because at the end when I submit my data using Inertia with Laravel I want the errors to display on the relevant modal.
I want to be able to keep track of which modal is open. I want to be able to close specific modals and open specific modals with a method. I would like to display the modal page where errors occur. For example, page 1 of 3 contains validation errors. Or an alternative to clicking next and getting errors on the fly for the current scope?
Any suggestions are welcome.
Here is my reusable modal vue component:
<script setup>
import {onMounted, reactive, watch} from 'vue'
import {Modal} from 'bootstrap'
const modal = reactive({});
let props = defineProps({
id: {
type: String,
required: true,
},
showModal: {
type: Boolean,
default: false,
},
});
onMounted(() => {
modal.value = new Modal('#' + props.id);
})
watch(
() => props.showModal,
show => {
modal.value.show()
},
)
</script>
<template>
<teleport to="body">
<div
:id="id"
class="modal fade"
tabindex="-1"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered max_630">
<div class="modal-content">
<div
v-if="$slots.title"
class="modal-header"
>
<h5 class="modal-title">
<slot name="title"/>
</h5>
<a
type="button"
data-bs-dismiss="modal"
aria-label="Close"
><span
class="iconify"
data-icon="ant-design:close-outlined"
/></a>
</div>
<div
v-if="$slots.body"
class="modal-body"
>
<slot name="body"/>
</div>
<div
v-if="$slots.footer"
class="modal-footer"
>
<slot name="footer"/>
</div>
</div>
</div>
</div>
</teleport>
</template>
This is how im using the reusable modal by defining 3 of them for 3 pages of inputs and the final page being the submission:
<script setup>
import Modal from '#/Components/Modal';
import {defineExpose, ref} from 'vue'
import {useForm} from "#inertiajs/inertia-vue3";
import BreezeInput from '#/Components/Input.vue';
import BreezeLabel from '#/Components/Label.vue';
import InputError from '#/Components/InputError.vue';
import Button from '#/Components/Button';
const form = useForm({
company: {
brand_name: null,
trading_name: null,
registered_name: null,
reg_no: null,
vat_no: null,
email: null,
telephone: null,
website_url: null
},
address: {
line1: null
}
})
const submit = () => {
form.post(route('dealership.store'), {
onError: (err) => {
// form.errors
},
onSuccess: () => {
}
});
};
let props = defineProps({
showModal: {
type: Boolean,
default: false,
},
});
</script>
<template>
<Button
class="blue_bg_button"
#click="showModal = !showModal"
>
<span
class="iconify"
data-icon="dashicons:plus-alt2"
/>
{{ __('Create Dealership') }}
</Button>
<Modal :id="'page1'" :showModal="showModal">
<template #title>
Create New Dealership
</template>
<template #body>
<h6 class="font_600 mb-4">Dealership Information</h6>
<div class="row">
<div class="col-6">
<div class="form-wrapper-block mb-4">
<BreezeLabel class="form-label" for="brand_name" value="Brand Name"/>
<BreezeInput id="brand_name" type="text" class="form-control" v-model="form.company.brand_name" placeholder="Brand Name"/>
<InputError :message="form.errors['company.brand_name']"></InputError>
</div>
</div>
<div class="col-6">
<div class="form-wrapper-block mb-4">
<BreezeLabel class="form-label" for="trading_name" value="Dealership Trading Name"/>
<BreezeInput id="trading_name" type="text" class="form-control" v-model="form.company.trading_name" placeholder="Trading Name"/>
<InputError :message="form.errors['company.trading_name']"></InputError>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="form-wrapper-block mb-4">
<BreezeLabel class="form-label" for="registered_name" value="Dealership Registration Name"/>
<BreezeInput id="registered_name" type="text" class="form-control" v-model="form.company.registered_name" placeholder="Dealership Registration Name"/>
<InputError :message="form.errors['company.registered_name']"></InputError>
</div>
</div>
<div class="col-6">
<div class="form-wrapper-block mb-4">
<BreezeLabel class="form-label" for="reg_no" value="Registration Number"/>
<BreezeInput id="reg_no" type="text" class="form-control" v-model="form.company.reg_no" placeholder="00/000/000"/>
<InputError :message="form.errors['company.reg_no']"></InputError>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="form-wrapper-block mb-4">
<BreezeLabel class="form-label" for="vat_no" value="VAT Number"/>
<BreezeInput id="vat_no" type="text" class="form-control" v-model="form.company.vat_no" placeholder="4333455555"/>
<InputError :message="form.errors['company.vat_no']"></InputError>
</div>
</div>
<div class="col-6">
</div>
</div>
<hr>
<h6 class="font_600 mb-4">Location</h6>
<div class="form-wrapper-block mb-4">
<BreezeLabel class="form-label" for="line1" value="Address Line"/>
<BreezeInput id="line1" type="text" class="form-control" v-model="form.address.line1" placeholder="12 Harrington Street, Cape Town, Cape Town City Centre"/>
<InputError :message="form.errors['address.line1']"></InputError>
</div>
<div class="pagination-wrapper">
<div class="pagination">
<span class="active"></span>
<span></span>
<span></span>
</div>
</div>
</template>
<template #footer>
<button type="button" class="blue_bg_button" data-bs-dismiss="page1" data-bs-toggle="modal" data-bs-target="#page2">Next</button>
<button type="button" class="edit_button" data-bs-dismiss="modal">Cancel</button>
</template>
</Modal>
<Modal :id="'page2'">
<template #title>
Create New Dealership
</template>
<template #body>
<h6 class="font_600 mb-4">Dealership Contact Details</h6>
<div class="row">
<div class="col-6">
<div class="form-wrapper-block mb-4">
<BreezeLabel class="form-label" for="dealer_email" value="Dealership Email"/>
<BreezeInput id="dealer_email" type="email" class="form-control" v-model="form.company.email" placeholder="Dealership Email"/>
<InputError :message="form.errors['company.email']"></InputError>
</div>
</div>
<div class="col-6">
<div class="form-wrapper-block mb-4">
<BreezeLabel class="form-label" for="telephone" value="Contact Number"/>
<BreezeInput id="telephone" type="text" class="form-control" v-model="form.company.telephone" placeholder="012 234 6789"/>
<InputError :message="form.errors['company.telephone']"></InputError>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="form-wrapper-block mb-4">
<BreezeLabel class="form-label" for="website_url" value="Dealership Website"/>
<BreezeInput id="website_url" type="text" class="form-control" v-model="form.company.website_url" placeholder="www.dealership.com"/>
<InputError :message="form.errors['company.website_url']"></InputError>
</div>
</div>
<div class="col-6">
</div>
</div>
<div class="pagination-wrapper">
<div class="pagination">
<span class="active"></span>
<span class="active"></span>
<span></span>
</div>
</div>
</template>
<template #footer>
<div class="d-flex align-items-center">
<a href="#" class="gray_7" data-bs-dismiss="modal" data-bs-toggle="modal" data-bs-target="#page1"><span class="iconify prev_ico" data-icon="ant-design:arrow-left-outlined"></span>
Previous</a>
</div>
<div>
<button type="button" class="edit_button" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="blue_bg_button" data-bs-dismiss="modal" data-bs-toggle="modal" data-bs-target="#page3">Next</button>
</div>
</template>
</Modal>
<Modal :id="'page3'">
<template #title>
Create New Dealership
</template>
<template #footer>
<div class="d-flex align-items-center">
<a href="#" class="gray_7" data-bs-dismiss="modal" data-bs-toggle="modal" data-bs-target="#page2"><span class="iconify prev_ico" data-icon="ant-design:arrow-left-outlined"></span>
Previous</a>
</div>
<div>
<button type="button" class="edit_button" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="blue_bg_button" :disabled="form.processing" #click="submit()">Add dealership</button>
</div>
</template>
</Modal>
</template>

$dispatch select change event to update button focus

Hello I have a select element I would like to set a buttons focus on change. My code is as follows. I have included a $dispatch but not sure I am doing it correctly
function data() {
return {
open: "tab 1",
tabs: [
{
value: "tab 1",
text: "Text for tab 1"
},
{
value: "tab 2",
text: "Text for tab 2"
},
{
value: "tab 3",
text: "Text for tab 3"
}
]
};
}
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine#v2.x.x/dist/alpine.min.js"></script>
<div x-data="data()" x-init="select = open, $watch('select', value => console.log(value))" $watch="('select', value => console.log(select))" class="w-full h-screen bg-gray-200 flex items-center justify-center">
<div class="flex flex-wrap gap-2">
<template x-for="btn in tabs" :key="btn.value">
<button x-on:selectchange=":focus = $event.detail.value === btn.value" x-text="btn.value" #click="open = btn.value, select = btn.value" class="bg-blue-400 px-6 py-4 rounded-sm border-b-4 border-blue-800 uppercase tracking-widest font-bold " :class="{'bg-blue-800 text-blue-300' : btn.value === open}">toggle</button>
</template>
<div class="w-full">
<form action="">
<select class="w-full appearance-none px-6 py-4 border border-blue-800 rounded-sm" name="" id="" x-model="select">
<template x-for="opt in tabs" x-on:change="$dispatch='selectchange',{value:opt.value}" :key="opt.value">
<option x-text="opt.value"></option>
</template>
</select>
</form>
</div>
<div>
<template x-for="txt in tabs">
<p x-text="txt.text" x-show="open === txt.value"></p>
</template>
</div>
</div>
</div>
Thanks in advance
$dispatch is a function you need to call. You also want to use a ref so you can focus your button easily.
<div x-data="data()" x-init="select = open, $watch('select', value => console.log(value))" $watch="('select', value => console.log(select))" class="w-full h-screen bg-gray-200 flex items-center justify-center">
<div class="flex flex-wrap gap-2">
<template x-for="btn in tabs" :key="btn.value">
<button x-ref="button" x-on:selectchange.window="$refs.button.focus()" x-text="btn.value" #click="open = btn.value, select = btn.value" class="bg-blue-400 px-6 py-4 rounded-sm border-b-4 border-blue-800 uppercase tracking-widest font-bold " :class="{'bg-blue-800 text-blue-300' : btn.value === open}">toggle</button>
</template>
<div class="w-full">
<form action="">
<select class="w-full appearance-none px-6 py-4 border border-blue-800 rounded-sm" name="" id="" x-model="select">
<template x-for="opt in tabs" x-on:change="$dispatch('selectchange', {value:opt.value})" :key="opt.value">
<option x-text="opt.value"></option>
</template>
</select>
</form>
</div>
<div>
<template x-for="txt in tabs">
<p x-text="txt.text" x-show="open === txt.value"></p>
</template>
</div>
</div>
</div>

Alpine.js bind the change of select back to x-data

I have two anchor tags whose #click directives? update my select options. I would like when the options are changes to update the value of activeTab to be either 0 or 1. I've been trying #change but no joy. Thanks in advance
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine#v2.x.x/dist/alpine.min.js"></script>
<div x-data="{activeTab : window.location.hash ? window.location.hash.substring(1) : 0, lessons:[{id:0,room:'online',description:'Online description'},{id:1,room:'in class',description:'in class description'}]}" x-init="select = lessons[0].room" class="w-full">
<nav class="w-full flex flex-no-wrap justify-between mb-8">
<template x-for="lesson in lessons">
<a href="#" #click.prevent="activeTab = lesson.id; window.location.hash = 0; select = lesson.room" class="focus:outline-none focus:text-teal-800 hover:text-teal-800 meta bold py-1 uppercase mr-1 flex items-center justify-between text-lg w-1/2 border-b-4 focus:border-teal-800 hover:border-teal-800 border-teal-600 tracking-widest text-teal-600"><span x-text="lesson.room"></span><svg class="w-6 h-6" width="6" height="6" viewBox="0 0 21 21" xmlns="http://www.w3.org/2000/svg">
<path d="m8.5.5-4 4-4-4" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" transform="translate(6 8)" /></svg></a>
</template>
</nav>
<template x-for="lesson in lessons" :key="lesson.id">
<div x-show="activeTab === lesson.id">
<p x-text="lesson.description" class="text-gray-800 mb-6">Online classes are streaemed to your device. You can atned a yoga class wherever there is a why-fi</p>
</div>
</template>
<form action="">
<fieldset class="border p-4">
<legend class="text-center text-xs uppercase tracking-widest text-orange-800 px-2">choose a classroom</legend>
<select class="relative uppercase text-lg tracking-widest text-teal-800 w-full border border-teal-800 px-5 py-4 focus:outline-none focus:border-shadow rounded" name="" id="" x-model="select">
<template x-for="lesson in lessons" :key="lesson.id">
<option :id="lesson.id"><span x-text="lesson.room"></span></option>
</template>
</select>
</fieldset>
</form>
</div>
Here is a simplified version of your code that works. I didn't really want to change your code, but I had to simplify it a bit to comprehend it. For example, activeTab and select seemed redundant, and I didn't understand the part about window.location.hash.
<script defer src="https://unpkg.com/alpinejs#3.x.x/dist/cdn.min.js"></script>
<div
x-data="{
activeTab: 0,
lessons: [
{ id: 0, room: 'online', description: 'Online description' },
{ id: 1, room: 'in class', description: 'In class description' }
],
}"
>
<nav>
<template x-for="lesson in lessons">
<a
href="#"
#click.prevent="window.location.hash = activeTab = lesson.id"
:style="activeTab === lesson.id ? 'font-weight:bold' : 'text-decoration:none'"
>
<span x-text="lesson.room"></span></a>
</template>
</nav>
<template x-for="lesson in lessons">
<div x-show="activeTab === lesson.id">
<p x-text="lesson.description"></p>
</div>
</template>
<form>
<fieldset>
<legend>choose a classroom</legend>
<select x-model.number="activeTab">
<template x-for="lesson in lessons">
<option :value="lesson.id" x-text="lesson.room"></option>
</template>
</select>
</fieldset>
</form>
</div>
JSFiddle
I believe the problem was a strict equality comparison (===) between values which were sometimes strings and sometimes integers. For example, "1" === 1 is never true.
I think there were two problems with your original code:
select wasn't declared part of x-data, thus it wasn't christened a "reactive" property, thus changing the value of the <select> had no actual effect
fix this by adding something like select: null to your x-data
that aside, there was still nothing to trigger the update of activeTab when the <select> was changed
binding lesson.id to the <option> values and the <select>'s value to activeTab with x-model.number (forgoing the select variable entirely) is how I chose to address this problem
this way the x-shows for the active tab trigger directly from a change to the <select>'s value
This didn't apply in your code as originally written, but keep in mind that an x-model on a <select> will always return strings, unless you use x-model.number to coerce to integer.

How do you use confirm dialogues in a custom Laravel Nova tool?

Is it possible to use the built in Laravel Nova confirm dialogue in your own tool? All I would like to use is interact with it how Nova does itself.
The docs are quite light on the JS topic, as the only built in UI you seem to be able to work with is the toasted plugin: https://nova.laravel.com/docs/1.0/customization/frontend.html#javascript
You can use <modal> component whenever you want.
Here is how it work internally in Nova:
<template>
<modal
data-testid="confirm-action-modal"
tabindex="-1"
role="dialog"
#modal-close="handleClose"
class-whitelist="flatpickr-calendar"
>
<form
autocomplete="off"
#keydown="handleKeydown"
#submit.prevent.stop="handleConfirm"
class="bg-white rounded-lg shadow-lg overflow-hidden"
:class="{
'w-action-fields': action.fields.length > 0,
'w-action': action.fields.length == 0,
}"
>
<div>
<heading :level="2" class="border-b border-40 py-8 px-8">{{ action.name }}</heading>
<p v-if="action.fields.length == 0" class="text-80 px-8 my-8">
{{ __('Are you sure you want to run this action?') }}
</p>
<div v-else>
<!-- Validation Errors -->
<validation-errors :errors="errors" />
<!-- Action Fields -->
<div class="action" v-for="field in action.fields" :key="field.attribute">
<component
:is="'form-' + field.component"
:errors="errors"
:resource-name="resourceName"
:field="field"
/>
</div>
</div>
</div>
<div class="bg-30 px-6 py-3 flex">
<div class="flex items-center ml-auto">
<button
dusk="cancel-action-button"
type="button"
#click.prevent="handleClose"
class="btn text-80 font-normal h-9 px-3 mr-3 btn-link"
>
{{ __('Cancel') }}
</button>
<button
ref="runButton"
dusk="confirm-action-button"
:disabled="working"
type="submit"
class="btn btn-default"
:class="{
'btn-primary': !action.destructive,
'btn-danger': action.destructive,
}"
>
<loader v-if="working" width="30"></loader>
<span v-else>{{ __('Run Action') }}</span>
</button>
</div>
</div>
</form>
</modal>
</template>
<script>
export default {
props: {
working: Boolean,
resourceName: { type: String, required: true },
action: { type: Object, required: true },
selectedResources: { type: [Array, String], required: true },
errors: { type: Object, required: true },
},
/**
* Mount the component.
*/
mounted() {
// If the modal has inputs, let's highlight the first one, otherwise
// let's highlight the submit button
if (document.querySelectorAll('.modal input').length) {
document.querySelectorAll('.modal input')[0].focus()
} else {
this.$refs.runButton.focus()
}
},
methods: {
/**
* Stop propogation of input events unless it's for an escape or enter keypress
*/
handleKeydown(e) {
if (['Escape', 'Enter'].indexOf(e.key) !== -1) {
return
}
e.stopPropagation()
},
/**
* Execute the selected action.
*/
handleConfirm() {
this.$emit('confirm')
},
/**
* Close the modal.
*/
handleClose() {
this.$emit('close')
},
},
}
</script>
Here is simplified example:
<modal>
<form
autocomplete="off"
class="bg-white rounded-lg shadow-lg overflow-hidden"
>
<div>
<heading :level="2" class="border-b border-40 py-8 px-8">test</heading>
test
</div>
<div class="bg-30 px-6 py-3 flex">
<div class="flex items-center ml-auto">
<button
type="button"
class="btn text-80 font-normal h-9 px-3 mr-3 btn-link"
>
{{ __('Cancel') }}
</button>
<button
ref="runButton"
type="submit"
class="btn-danger"
>
<span>{{ __('Run Action') }}</span>
</button>
</div>
</div>
</form>
</modal>
You need to create a new component in the same folder of Tool.vue
I'll attach the component I used here
Then in the "handleConfirm" method, you can add a Ajax call to API
You can add you logic in that API.
You can find the API file in path, ToolName/routes/api.php
/* CustomModal.vue */
<template>
<modal tabindex="-1" role="dialog" #modal-close="handleClose">
<form #keydown="handleKeydown" #submit.prevent.stop="handleConfirm" class="bg-white rounded-lg shadow-lg overflow-hidden w-action">
<div>
<heading :level="2" class="border-b border-40 py-8 px-8">Confirm action</heading>
<p class="text-80 px-8 my-8"> Are you sure you want to perform this action? </p>
</div>
<div class="bg-30 px-6 py-3 flex">
<div class="flex items-center ml-auto">
<button type="button" #click.prevent="handleClose" class="btn btn-link dim cursor-pointer text-80 ml-auto mr-6">
Cancel
</button>
<button :disabled="working" type="submit" class="btn btn-default btn-primary">
<loader v-if="working" width="30"></loader>
<span v-else>Confirm</span>
</button>
</div>
</div>
</form>
</modal>
</template>
<script>
export default {
methods: {
handleConfirm() {
// Here you can add an ajax call to API and you can add your logic there.
},
handleClose() {
// Logic to hide the component
},
},
}
</script>
For more detailed explanation : https://medium.com/vineeth-vijayan/how-to-use-confirm-dialogs-in-a-laravel-nova-tool-b16424ffee87

Can't access component method inside my blade file

I am trying to access a method inside my blade file, with #click but I am getting an error
signup-modal.vue
<template>
<div>
<div v-if="modal" class="animated fadeIn fixed z-50 pin overflow-auto bg-black flex">
<div class="animated fadeInUp fixed shadow-inner max-w-md md:relative pin-b pin-x align-top m-auto justify-end md:justify-center p-8 bg-white md:rounded w-full md:h-auto md:shadow flex flex-col">
<p class="text-xl leading-normal mb-8 text-center">
{{ __("Sign up to name to start socializing") }}
</p>
<div class="justify-center">
<form action="/auth/register" method="post">
<div class="mb-4">
<label class="block text-grey-darker text-sm font-bold mb-2" for="username">
{{ __("Name" )}}
</label>
<input class="shadow appearance-none border rounded w-full py-2 px-3 text-grey-darker leading-tight" id="username" type="text" placeholder="Username">
</div>
<div class="mb-4">
<label class="block text-grey-darker text-sm font-bold mb-2" for="username">
{{ __("Email" )}}
</label>
<input class="shadow appearance-none border rounded w-full py-2 px-3 text-grey-darker leading-tight" id="username" type="text" placeholder="Username">
</div>
<div class="mb-4">
<label class="block text-grey-darker text-sm font-bold mb-2" for="username">
{{ __("Password" )}}
</label>
<input class="shadow appearance-none border rounded w-full py-2 px-3 text-grey-darker leading-tight" id="username" type="text" placeholder="Username">
</div>
<div class="flex items-center justify-end">
<button class="bg-teal hover:bg-teal-dark text-white font-bold py-2 px-4 rounded" type="button">
{{ __("Sign up") }}
</button>
</div>
</form>
</div>
<span #click="toggleModal" class="absolute pin-t pin-r pt-4 px-4">
<svg class="h-6 w-6 text-grey hover:text-grey-darkest" role="button" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><title>Close</title><path d="M14.348 14.849a1.2 1.2 0 0 1-1.697 0L10 11.819l-2.651 3.029a1.2 1.2 0 1 1-1.697-1.697l2.758-3.15-2.759-3.152a1.2 1.2 0 1 1 1.697-1.697L10 8.183l2.651-3.031a1.2 1.2 0 1 1 1.697 1.697l-2.758 3.152 2.758 3.15a1.2 1.2 0 0 1 0 1.698z"/></svg>
</span>
</div>
</div>
</div>
</template>
<script>
export default {
data: function()
{
return {
modal: false
}
},
methods: {
toggleModal: function() {
console.log("djdjd")
//this.modal = !this.modal
}
}
}
</script>
app.js
/**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./bootstrap');
window.Vue = require('vue');
Vue.component('signup-modal', require('./components/signup-modal.vue'));
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
const app = new Vue({
el: '#app'
});
My blade file:
<div id="app">
<button class="bg-blue w-full rounded-full text-white py-2 mb-2" #click="toggleModal">
{{ __("Sign up") }}
</button>
</div>
<div>
<signup-modal></signup-modal>
</div>
</div>
As you can see in my blade file I am trying to access my components method toggleModal but I am getting an error:
app.js:36520 [Vue warn]: Property or method "toggleModal" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
(found in <Root>)
warn # app.js:36520
warnNonPresent # app.js:37826
has # app.js:37859
(anonymous) # VM374:3
Vue._render # app.js:40471
updateComponent # app.js:38715
get # app.js:39069
Watcher # app.js:39058
mountComponent # app.js:38722
Vue.$mount # app.js:44467
Vue.$mount # app.js:46866
Vue._init # app.js:40567
Vue # app.js:40656
(anonymous) # app.js:13896
__webpack_require__ # app.js:20
(anonymous) # app.js:13869
__webpack_require__ # app.js:20
(anonymous) # app.js:63
(anonymous) # app.js:66
app.js:36520 [Vue warn]: Invalid handler for event "click": got undefined
Why is this and how can I fix it?
To achieve what I wanted to do, I went the event-based way. For example, in my component, I added the method mounted, and added the following:
mounted()
{
eventHub.$on('signup-click', this.toggleModal)
}
And my main Vue method I added a simple event emitter method like so:
const app = new Vue({
el: '#app',
methods: {
generateEvent: (event) => {
eventHub.$emit(event);
}
}
});
And then in my blade file, I simple called that method like so:
<button class="bg-blue w-full rounded-full text-white py-2 mb-2" #click="generateEvent('signup-click')">
{{ __("Sign up") }}
</button>
Which simple emits the event, so my component listens to it, then calls that child method.

Resources