click event as props in Vue.js - vue.js

I created a dynamic overlay component with Vue.js to handle the close event, when we click on the screen away from the intended object the object closes my problem here the click event does not work here's my code
<template>
<button
v-if="action"
#click="clicked"
tabindex="-1"
class="fixed z-40 w-full h-full inset-0 bg-black opacity-50 cursor-default"
></button>
</template>
<script>
export default {
name: "Overlay",
props: {
action: Boolean,
},
methods: {
clicked() {
if (this.action === true) {
return false
}
}
}
};
</script

Usually you are not allowed to update properties passed to the component.
The proper way should be for you to emit the click from where it is used like:
clicked() {
this.$emit("clicked");
}
Then when you use the overlay component like:
<overlay #clicked="doSomethingHere"></overlay>
You can alter your toggle variable outside of the component, but within the component you should use data() { action: false } instead of attempting to update properties.
Finally you can read more about properties here: https://v2.vuejs.org/v2/guide/components-props.html

i was looking for the same thing but my solution was to use v-if without if true component doesn't fire
<Toast
v-if="show"
type="error"
description="desc"
/>
<button #click="show = !show">Toast active !</button>

Related

VueJS2: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders

I'm creating very simple Popup Modal Using Vuejs2 and TailwindCss. However i encounter the error like below, when i'm tring to click on Button..
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders.
In Parent Component
// CardModal
<template>
<div class="bg-white">
<div v-if="showing">
Modal
</div>
</div>
</template>
<script>
export default {
data() {
return {
showing: false,
}
}
}
</script>
Child Components
<button #click="showing = true" class="px-4 my-4 mx-3 bg-blue-400 py-1 font-bold rounded text-white">
Add Product
</button>
<!-- Modal -->
<cardModal :showing="showing" />
// Script
props: {
showing: {
// required: true,
type: Boolean,
}
},
Thanks in advance...
It's hard to understand your code but you can't change value of prop in your child component directly instead you can emit an event to your parent which change the value of prop for you.
e.g your child component which has
<template>
#click="$emit('show',true)"
</template>
//
props: {
showing: {
// required: true,
type: Boolean,
}
}
your parent
<cardModal :showing="showing" #show="showing=$event" />

Prevent Bootstrap-Vue Modal From Opening

I am using the Bootstrap-Vue modal and want to stop it from opening at times. I'm not sure with how to block the default behavior.
<b-img
ref='cal-modal-button'
id='cal-modal-button'
class="cal-icon"
v-bind:src="imagePath + calimage"
v-b-modal.date-time-modal
>
</b-img>
And then the stripped down modal is set up as such:
<b-modal id="date-time-modal" name="header-modal" ref="date-time-modal" hide-footer title="Set Date and Time">
...
</b-modal>
Is there a way to prevent it from popping up without using JQuery?
From the documentation you can cancel modal by using show event :
<template>
// ...
<b-modal #show="onShow" ... />
</template>
<script>
export default {
// ...
data:() => ({
modalDisabled:true
}),
methods: {
onShow(bvModalEvt) {
if(this.modalDisabled) {
bvModalEvt.preventDefault()
}
}
}
}
</script>
show event reference :
https://bootstrap-vue.js.org/docs/components/modal/#comp-ref-b-modal-events
Always emits just before modal is shown. Cancelable
BvModalEvent object. Call bvModalEvt.preventDefault() to cancel show

Vue component error: Expected Function, got String

I'm using ionic with vue to develop an app. I made a custom button and want to include in another component. I'm trying to assign a function to the button but doesnt seem to work. The error i got is this:
[Vue warn]: Invalid prop: type check failed for prop "onClick". Expected Function, got String with value "addTodo".
First time using vue.Thanks in advance.
Button component
<template>
<ion-footer>
<ion-button fill="outline" expand="block" color="primary" #click="onClick">
<ion-ripple-effect></ion-ripple-effect>
{{text}}
</ion-button>
</ion-footer>
</template>
<script>
export default {
props: {
onClick:Function,
text:String,
}
}
</script>
Another Component
<template>
<ion-row>
<ion-col>
<main-btn text="Add Activity" onClick="addTodo"></main-btn>
</ion-col>
</ion-row>
</ion-grid>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
todos: []
}
},
methods: {
addTodo() {
this.$router.push({path: '/todos/add'})
}
},
created() {
axios.get('http://localhost:3001/todos')
.then(res => this.todos = res.data)
}
}
</script>
Just change it up, you don't need to pass the function as a prop.
In your button component:
#click="$emit('click')"
In your "Another Component"
<main-btn text="Add Activity" #click="addTodo"></main-btn>
Just bubble up the click event from the child component.
Your going backwards against the way Vue is intended to work. You always want to pass Props Down which consist of data the child components need and emit events upwards to the parents to handle the necessary function calls.
Your child component "main-btn" should look more like below
<ion-button fill="outline" expand="block" color="primary" #click="$emit("onClick")">
<ion-ripple-effect></ion-ripple-effect>
{{text}}
</ion-button>
This will allow any parent components to look for the onClick Event emitted by the child component and react accordingly. In your case the parent component only needs to change slightly.
<ion-col>
<main-btn text="Add Activity" #onClick="addTodo"></main-btn>
</ion-col>
The parent component is looking for an onClick event and reacts accordingly by calling its addTodo function
https://v2.vuejs.org/v2/guide/components.html#Listening-to-Child-Components-Events

Modal component in VueJS

I am building a web app. I have few components that are modals (that show data about customers, lessons, ...).
I search a way to show one of the components easily.
And if possible doing lazy loading.
What's the best way to perform this?
Check out conditional rendering, specifically v-if. This would only load the modal if the button is clicked for example.
https://v2.vuejs.org/v2/guide/conditional.html#v-if
Single page component:
<template>
<div>
<div
v-if="showModal"
class="modal">
Stuff
</div>
<button #click="toggleModal">
Toggle Modal
</button>
</div>
</template>
<script>
export default {
data () {
return {
showModal: false
}
},
methods: {
toggleModal() {
this.showModal = !this.showModal
}
},
}
</script>

Vue `vm.$on()` callback not working in parent when event is emitted from dynamic component child

I'm experiencing a problem where a custom event (swap-components) emitted from a dynamic component (A.vue or B.vue) is not being listened to correctly in the parent of the dynamic component (HelloWorld.vue).
Here is the source on GitHub (created using vue cli 3).
Here is a live demo showing the problem.
In the live demo, you'll see that clicking the button in the dynamic component with background color DOES NOT change the dynamic component. But when clicking the button below the background color (which originates in the HelloWorld.vue parent), the dynamic component DOES INDEED change.
Why is this happening and how to fix it?
Below I'll copy over the contents of the 3 main files of interest into this post:
HelloWorld.vue (the parent)
A.vue (sub component used in dynamic component)
B.vue (sub component used in dynamic component)
HelloWorld.vue:
<template>
<div>
<h1>The dynamic components ⤵️</h1>
<component
:is="current"
v-bind="dynamicProps"
></component>
<button
#click="click"
>Click me to swap components from within the parent of the dynamic component</button>
</div>
</template>
<script>
import A from "./A.vue";
import B from "./B.vue";
export default {
data() {
return {
current: "A"
};
},
computed: {
dynamicProps() {
return this.current === "A" ? { data: 11 } : { color: "black" };
}
},
methods: {
click() {
this.$emit("swap-components");
},
swapComponents() {
this.current = this.current === "A" ? "B" : "A";
}
},
mounted() {
this.$nextTick(() => {
// Code that will run only after the
// entire view has been rendered
this.$on("swap-components", this.swapComponents);
});
},
components: {
A,
B
},
props: {
msg: String
}
};
</script>
A.vue:
<template>
<section id="A">
<h1>Component A</h1>
<p>Data prop sent from parent: "{{ data }}"</p>
<button #click="click">Click me to swap components from within the dynamic component</button>
</section>
</template>
<script>
export default {
props: ["data"],
methods: {
click() {
this.$emit("swap-components");
}
}
};
</script>
B.vue:
<template>
<section id="B">
<h1>Component B</h1>
<p>Color prop sent from parent: "{{ color }}"</p>
<button #click="click">Click me to swap components from within the dynamic component</button>
</section>
</template>
<script>
export default {
props: ["color"],
methods: {
click() {
this.$emit("swap-components");
}
}
};
</script>
I'm guessing this is because the event listener is listening for a swap-components event emitted by the parent component itself. Perhaps you can fix that by listening for a swap-components event from the child component then emitting an event on the parent component.
<template>
<div>
<h1>The dynamic components ⤵️</h1>
<component
:is="current"
v-bind="dynamicProps"
#swap-components="$emit('swap-components')"
></component>
<button
#click="click"
>Click me to swap components from within the parent of the dynamic component</button>
</div>
</template>
Or you can call your method directly when the event is emitted by the child component ..
<template>
<div>
<h1>The dynamic components ⤵️</h1>
<component
:is="current"
v-bind="dynamicProps"
#swap-components="swapComponents"
></component>
<button
#click="click"
>Click me to swap components from within the parent of the dynamic component</button>
</div>
</template>
this is not bound to the context anymore when you use function. It is only limited to the function scope. Use arrow function to let this bound to the parent context.
Change:
this.$nextTick(function() {
With:
this.$nextTick(() => {