Vue renders v-if=true. But if I change bool true to false,
vue doesn't re-render to v-else div.
How should it be? Is there any way to re-render?
Here is my code:
<template>
<div v-if="bool">
true
</div>
<div v-else>
false // if button pressed, i should be shown!!!!
</div>
<button :click='onClickEvent()'>click!!!!!!</button>
</template>
<script>
export default {
data: function () {
return {
bool: true
};
},
created() {
},
mounted(){
}
methods: {
onClickEvent: function(){
this.bool= false
}
}
};
</script>
I tried everything I could think of.
You should not be binding with :click instead it should be #click="onClickEvent".
https://vuejs.org/guide/essentials/event-handling.html
Related
I have this component:
<template>
<div class="hello">
<div>
My prop: {{ myprop }}?
</div>
<div>
<button class="fas fa-lock-open lock" #click="changeText()">Click</button>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'StartPage',
props: {
myprop: {
type: String
}
},
model: {
prop: 'myprop',
event: 'click'
},
methods: {
changeText () {
this.$emit('click', 'sometext')
console.log('this.myprop', this.myprop)
}
}
})
</script>
Im using vue v3. Everytime I click on the button, I still see the text "My prop: ?" in the browser.
And in the console I can see: "this.myprop undefined" every time I click on the button.
What am I doing wrong?
As per my understanding, You are trying to update the prop text on click of button from the child component. If Yes, you can achieve it simply by emitting a new text and updating that in the parent component.
Live Demo :
const ShowPropText = {
template: `<div class="hello">
<div>
My prop: {{ myprop }}
</div>
<div>
<button class="fas fa-lock-open lock" #click="changeText()">Click</button>
</div>
</div>`,
props: ['myprop'],
methods: {
changeText() {
this.$emit('click-event', 'sometext')
}
}
}
const app = Vue.createApp({
components: {
'show-prop-text': ShowPropText
},
data() {
return {
text: 'This is default text'
}
},
methods: {
methodCall(e) {
this.text = e;
}
}
})
app.mount('#app')
<script src="https://cdn.jsdelivr.net/npm/vue#next"></script>
<div id="app">
<show-prop-text :myprop="text" #click-event="methodCall"></show-prop-text>
</div>
In my parent component I have a button and child component:
<div> #click="editMe(edit)" />
<edit-team :openModal="openModal"/>
</div>
export default {
data() {
return {
openModal: false,
};
},
method: {
editMe(edit) {
this.openModal = true;
},
}
}
So after I click the editMe button, I am expecting openModal becomes true and goes true to child component.
<template>
<el-dialog
:visible.sync="modal"
/>
</template>
<script>
export default {
props: {
openModal: {
type: Boolean,
required: true,
},
},
data() {
return {
modal: this.openModal,
};
},
</script>
But unfortunately, the modal is not opening because props comes as false always. I assigned openModal to new variable because it was giving me a warning about mutating props. So how do you think I can send the props in right value?
In child just try this
<template>
<el-dialog
:visible.sync="openModal"
/>
</template>
<script>
export default {
props: {
openModal: {
type: Boolean,
required: true,
},
},
},
</script>
If you have sibilngs components and you need to retrieve data, you can use the emit keyword and emit events
Then it will work like this :
The sibling emit the event to show the modal
The parent update the showModalData to true
This child is re-rendered
Vue.component('modal', {
template: '#modal',
props: ['show'],
});
Vue.component('buttonModal', {
template: '#buttonModal',
methods: {
showModal(){
this.$emit('show-modal-button', true)
}
}
});
new Vue({
el: '#app',
data: () => ({
showModalData: false
}),
methods: {
editMe() {
this.showModalData = true
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<p>this is the parent</p>
<hr>
<button-modal #show-modal-button="editMe">Show modal</button-modal>
<hr>
<modal :show="showModalData" />
</div>
<template id="modal">
<div>
props show : {{ show }}
<h2 v-if="show">This is the modal</h2>
</div>
</template>
<template id="buttonModal">
<div>
<p>This is the sibilng</p>
<button #click="showModal"> Show the modal through sibiling components </button>
</div>
</template>
In this project, we can login from login.vue by clicking login button and if it is success then we can see Lnb.vue in dashboard.vue
I thought if i code like this then pageSso will be 1 when I check the checkbox in login.vue in Lnb.vue then it will not show only "Account" menu.
When I used console.log(pageSso) at mounted cycle it showed pageSso was 0. What would be the problem?
store/store.js
export const state = () => ({
pageSso: 0,
})
export const getters = {
pageSso: (state) => state.pageSso,
}
export const mutations = {
setPageSso(state, data) {
console.log('mutations setPageSso data', data)
state.pageSso = data
}
}
export const actions = {
setPageSso({
commit
}, data) {
console.log('actions setPageSso data', data)
commit('setPageSso', data)
},
}
pages/login.vue
<template>
<input
class="checkbox_sso"
type="checkbox"
v-model="sso"
true-value="1"
false-value="0" >SSO checkbox
<button class="point" #click="submit">login</button>
</template>
<script>
export default {
data() {
return {
sso: '',
}
},
computed: {},
methods: {
submit() {
this.$store.dispatch('store/setPageSso', this.sso)
//this.$store.dispatch('store/login', data)
},
</script>
pages/dashboard.vue
<template>
<div class="base flex">
<Lnb />
<div class="main">
<Gnb />
<nuxt-child />
</div>
</div>
</template>
<script>
import Lnb from '#/components/Lnb'
import Gnb from '#/components/Gnb'
export default {
components: {
Lnb,
Gnb
},
mounted() {},
}
</script>
components/Lnb.vue
<template>
<ul>
<li :class="{ active: navbarState == 7 ? true : false }">
<a href="/dashboard/settings">
<img src="../assets/images/ico_settings.svg" alt="icon" /> Settings
</a>
</li>
<li v-show="pageSso != 1" :class="{ active: navbarState == 8 ? true : false }">
<a href="/dashboard/user">
<img src="../assets/images/ico_user.svg" alt="icon" />
Account
</a>
</li>
</ul>
</template>
<script>
import {
mapState
} from 'vuex'
export default {
data() {
return {}
},
computed: {
...mapState('store', {
// navbarState: (state) => state.navbarState,
pageSso: (state) => state.pageSso,
}),
},
mounted() {
console.log('pageSso ->', this.pageSso);
},
methods: {
},
}
</script>
Your console.log(pageSso) logs 0 because the mounted hook of Lnb.vue happens once, and it happens when the component is inserted into the DOM.
You insert Lnb into the DOM unconditionally in this line of dashboard.vue:
<Lnb />
and this is roughly when it's mounted hook is triggered.
Your pageSso seems to be changed only after you triggered the submit() method, which — I guess — happens way later, when you submit the login form.
Your Lnb.vue currently is always mounted. If you don't want to show it until pageSso is equal to 1, add a v-if on it in dashboard.vue like this:
<Lnb v-if="pageSso === 1" />
You currently don't have pageSso variable in dashboard.vue, you must take it from the store.
N.B.: Mind the difference between v-show and v-if directives: v-show only hides the component with display: none; while v-if actually removes or inserts the component from/to the DOM. With v-show, the component gets mounted even if you don't see it. With v-if, the component's mounted hook will fire each time the condition evaluates to true.
I am trying to mount a component on a function, it works fine. However I've got it setup so that it destroys the div after X amount of seconds. Then when I try and add the compoent again its removed the base div. I'm not sure how to fix this though...
Component:
<template>
<div>
<b-alert show dismissible variant="danger">
<i class="mdi mdi-block-helper mr-2"></i>{{ text }}
</b-alert>
</div>
</template>
<script>
export default {
name: "alertDanager",
props: {
text: null
},
created() {
setTimeout(() => this.destoryEl(), 5000);
},
methods: {
destoryEl() {
this.$destroy();
this.$el.parentNode.removeChild(this.$el);
}
}
};
</script>
Spawning the component in
const DangerAlertExtended = Vue.extend(dangerAlert);
const error = new DangerAlertExtended({ propsData: { text: "Error message" } });
error.$mount("#error");
I'm not sure how to make it stop overwriting the #error div...
Why not let v-if exclude it from the DOM instead of removing the element? Alternatively, it could be hidden but remain in the DOM with v-show (that's probably what I would do, unless there's a specific reason you need for it to not be in the DOM). I think it's generally better to let Vue manage the DOM rather than manipulate yourself.
<template>
<div v-if="showAlert">
<b-alert show dismissible variant="danger">
<i class="mdi mdi-block-helper mr-2"></i>{{ text }}
</b-alert>
</div>
</template>
<script>
export default {
name: "alertDanager",
props: {
text: null,
showAlert: true
},
created() {
setTimeout(() => this.hideAlert(), 5000);
},
methods: {
hideAlert() {
this.showAlert = false
}
}
}
</script>
I'm building simple modal component with Vue. I want to use this component in a parent components and to be able to toggle it from the parent.
This is my code now of the modal component:
<script>
export default {
name: 'Modal',
data() {
return {
modalOpen: true,
}
},
methods: {
modalToggle() {
this.modalOpen = !this.modalOpen
},
},
}
</script>
<template>
<div v-if="modalOpen" class="modal">
<div class="body">
body
</div>
<div class="btn_cancel" #click="modalToggle">
<i class="icon icon-cancel" />
</div>
</div>
</template>
I use the v-if to toggle the rendering and it works with the button i created inside my modal component.
However my problem is: I don't know how to toggle it with simple button from parent component. I don't know how to access the modalOpen data from the modal component
Ok, let's try to do it right. I propose to make a full-fledged component and control the opening and closing of a modal window using the v-model in parent components or in other includes.
1) We need declare prop - "value" in "props" for child component.
<script>
export default {
name: 'Modal',
props: ["value"],
data() {
return {
modalOpen: true,
}
},
methods: {
modalToggle() {
this.modalOpen = !this.modalOpen
},
},
}
</script>
2) Replace your "modalToggle" that:
modalToggle() {
this.$emit('input', !this.value);
}
3) In parent components or other includes declare "modal=false" var and use on component v-model="modal" and any control buttons for modal var.
summary
<template>
<div v-if="value" class="modal">
<div class="body">
body
</div>
<div class="btn_cancel" #click="modalToggle">
<i class="icon icon-cancel" />
</div>
</div>
</template>
<script>
export default {
name: "Modal",
props: ["value"],
methods: {
modalToggle() {
this.$emit("input", !this.value);
}
}
};
</script>
Example:
Vue.component('modal', {
template: '<div v-if="value" class="modal"><div class="body">modal body</div><div class="btn_cancel" #click="modalToggle">close modal<i class="icon icon-cancel" /></div></div>',
props: ["value"],
methods: {
modalToggle() {
this.$emit('input', !this.value);
}
}
});
// create a new Vue instance and mount it to our div element above with the id of app
var vm = new Vue({
el: '#app',
data:() =>({
modal: false
}),
methods: {
openModal() {
this.modal = !this.modal;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div #click="openModal">Btn modal</div>
<modal v-model="modal"></modal>
</div>
With your current implementation I would suggest you to use refs
https://v2.vuejs.org/v2/guide/components-edge-cases.html#Accessing-Child-Component-Instances-amp-Child-Elements
So in your parent component add ref="child" to modal (child) component and then open your modal by calling this.$refs.child.modalToggle()
You can use an "activator" slot
You can use ref="xxx" on the child and access it from the parent