I am new to Vue.js and ElementUI and having issues opening dialog from dropdown menu.
I am using Vue 2.5.2 and ElementUI: 2.3.4
I tried to follow the solution from
Vue.js - Element UI - Nested dialog won't open - v-if v-show but no luck.
Problem:
Dialog not showing up after clicking the dropdown menu item.
Thanks!
console.clear()
let popupData;
Vue.component('popup', {
name: "popup",
template: '#popup',
props : ['showDialog'],
data(){
return {
show: this.showDialog,
data: "Hello"
}
},
watch: {
showDialog: function(n,o){
this.show = this.showDialog;
}
},
methods: {
updateShowDialog(isVisible) {
if (isVisible) return false;
this.$emit('update:showDialog', false )
}
},
created:function (){
},
});
var vm = new Vue({
el: '#app',
data: {
showDialog: false,
},
methods: {
}
});
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<div id="app">
<el-dropdown>
<span class="el-dropdown-link">
Dropdown List<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item #click.native="showDialog = true">Show Component PopUp
<popup :show-dialog.sync="showDialog"></popup>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
<template id="popup">
<el-dialog :visible.sync="show" #visible-change="updateShowDialog" >{{data}}</el-dialog>
</template>
From de element.io docs, the el-dropdown-item do not have a #click event, you must use command-event in dropdown: http://element.eleme.io/#/en-US/component/dropdown#command-event
<div id="app">
<el-dropdown #command="onCommandDropdown">
<span class="el-dropdown-link">
Dropdown List<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="show-popup">
Show Component PopUp
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<popup :show-dialog.sync="showDialog"></popup>
</div>
<script type="x-template" id="popup">
<el-dialog title="Modal Title" :visible="showDialog" #close="onClose">
<span>{{ data }}</span>
</el-dialog>
</script>
The js part:
Vue.component('popup', {
template: '#popup',
props: ['showDialog'],
data() {
return {
show: this.showDialog,
data: "Hello modal!"
}
},
watch: {
showDialog(newValue) {
this.show = newValue;
}
},
methods: {
onClose() {
this.show = false;
this.$emit('update:showDialog', false);
}
}
});
new Vue({
el: '#app',
data: {
showDialog: false
},
methods: {
onCommandDropdown(command) {
if (command === 'show-popup') {
this.showDialog = true;
}
}
}
});
See working fiddle: https://jsfiddle.net/rafaph/pefwgL7y/2/
Related
When does an element become available in the dom after using a vue v-if? I would have thought you could do a query selector on the element after the v-if evaluates to true?
In the below code I need to get the .test element once the popout is shown but it shows as null - how do I get it?
new Vue({
el: "#app",
data() {
return {
showPopout: false,
};
},
methods: {
buttonClick(day) {
this.showPopout = true;
console.log(document.querySelector('.test'));
},
},
});
<script src="https://unpkg.com/vue#2.6.14/dist/vue.js"></script>
<div id='app'>
<span #click="buttonClick">show popout</span>
<div v-if="showPopout"><span class="test">test</span></div>
</div>
It will be there after nextTick
new Vue({
el: "#app",
data() {
return {
showPopout: false,
};
},
methods: {
buttonClick(day) {
this.showPopout = true;
this.$nextTick(() => {
console.log(document.querySelector('.test'));
});
},
},
});
<script src="https://unpkg.com/vue#2.6.14/dist/vue.js"></script>
<div id='app'>
<span #click="buttonClick">show popout</span>
<div v-if="showPopout"><span class="test">test</span></div>
</div>
I'm working with BootstrapVue.
I need to emit a value to my parent.vue - but my code line this.$emit('info', this.hide); doesn't work out.
If I console.log(this.hide) i get my value correct in this case false, otherwise if my if-statement is correct I get it true.
What is the mistake in here?
script of my child.vue:
data(){
return {
hide: true,
}
}
mounted() {
if (statement) {
if(some statement) {
//do something
} else {
this.hide = false;
console.log(this.hide); //HERE I GET CORRECT VALUE
this.$emit('info', this.hide); //THIS DOESNT WORK
}
}
}
How it should work in my parent.vue:
<template>
<div #info="info">
<div> //THIS DIV SHOULD BE SHOWN IF this.hide = false
</div>
<div> //THIS DIV SHOULD BE SHOWN IF this.hide = true
</div>
</div>
</template>
Try something like following snippet :
Vue.component('Child', {
template: `
<div class="">
child
<button #click="changeHide">change hide</button>
</div>
`,
data(){
return {
hide: true,
}
},
methods: {
changeHide() {
this.hide = !this.hide
this.sendInfo()
},
sendInfo() {
this.$emit('info', this.hide);
}
},
mounted() {
//if (statement) {
//if(some statement) {
//do something
//} else {
this.hide = false;
this.sendInfo()
//}
}
})
new Vue({
el: '#demo',
data(){
return {
info: null,
}
},
methods: {
setInfo(val) {
this.info = val
}
}
})
Vue.config.productionTip = false
Vue.config.devtools = false
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div v-if="!info"> //THIS DIV SHOULD BE SHOWN IF this.hide = false
</div>
<div v-if="info"> //THIS DIV SHOULD BE SHOWN IF this.hide = true
</div>
<p>from child info is: {{ info }}</p>
<Child #info="setInfo" />
</div>
Ideally in App.vue (Parent)
you should have something like
<login #info="someHandler"></login>
there is no need to go for a child component if you gonna jus use to manage some logic. It is appropriate only if have some contents in the template.
Also placing emit handler on some div. Thats not how emit works
Below is a simple working example
App.vue (parent)
<template>
<h1>{{ title }}</h1>
<Child #changeTitle="ChangeT($event)" />
</template>
<script>
import Child from "./components/Child"
export default{
name:'App',
components: {
Child,
},
data()
{
return{
title:'Rick Grimes'
}
},
methods:{
ChangeT(title)
{
this.title=title;
},
}
</script>
<style></style>
Child.vue
<template lang="html">
<button type="button" #click='passEvent'> Update me</button>
</template>
<script>
export default {
name:'Child',
methods:{
passEvent()
{
this.$emit('changeTitle','Awesome ')
}
}
}
</script>
<style lang="css" scoped>
</style>
we are working with injection of dynamic components by server response, but once the user has approved a step, we will prevent him from going back to the steps he has already approved.
HTML
<div id="app">
<div>
<form-wizard #on-complete="onComplete">
<tab-content v-for="tab in tabs"
v-if="!tab.hide"
:key="tab.title"
:title="tab.title"
:icon="tab.icon">
<component :is="tab.component"></component>
</tab-content>
</form-wizard>
</div>
</div>
JS
Vue.use(VueFormWizard)
Vue.component('step1', {
template:` <div> My first tab content <br>
</div>`
}
)
Vue.component('step2', {
template:`<div> My second tab content </div>`
})
Vue.component('step3', {
template:`<div> My third tab content </div>`
})
Vue.component('step4', {
template:`<div> Yuhuuu! This seems pretty damn simple </div>`
})
new Vue({
el: '#app',
data() {
return {
tabs: [{title: 'Personal details', icon: 'ti-user', component: 'step1'},
{title: 'Is Logged In?', icon: 'ti-settings', component: 'step2', hide: false},
{title: 'Additional Info', icon: 'ti-location-pin', component: 'step3'},
{title: 'Last step', icon: 'ti-check', component: 'step4'},
],
}
},
methods: {
onComplete: function(){
alert('Yay. Done!');
}
}
})
but we have not found answers in the documentation if suddenly someone has had this problem and can tell us how to solve it, I would appreciate it, thanks.
Once the user has approved a step, we will prevent him from going back
to the steps he has already approved.
Validate going forward, then simply remove the back button.
I did some tests and the beforeTabSwitch doesn't fire if going backwards props.prevTab(), shame as you could then do it in the validate call.
Here is an example, which validates going forward and removes the Previous button and prevents navigating via the header (wizard-step).
Vue.use(VueFormWizard)
Vue.component('step1', {
template: ` <div> My first tab content</div>`,
data: () => ({
name: ''
}),
methods: {
validate() {
// change `true` to things checked on model, beyond scope of question
this.$emit('on-validate', this.$data, true)
return true
}
}
})
Vue.component('step2', {
template: `<div> My second tab content </div>`,
data: () => ({
logged_in_yada: ''
}),
methods: {
validate() {
this.$emit('on-validate', this.$data, true)
return true
}
}
})
Vue.component('step3', {
template: `<div> My third tab content </div>`,
data: () => ({
additional_info: ''
}),
methods: {
validate() {
this.$emit('on-validate', this.$data, true)
return true
}
}
})
Vue.component('step4', {
template: `<div> Yuhuuu! This seems pretty damn simple </div>`,
data: () => ({
last_step: ''
}),
methods: {
validate() {
this.$emit('on-validate', this.$data, true)
return true
}
}
})
new Vue({
el: '#app',
data() {
return {
tabModel: {},
tabs: [{
title: 'Personal details',
icon: 'ti-user',
component: 'step1'
},
{
title: 'Is Logged In?',
icon: 'ti-settings',
component: 'step2',
hide: false
},
{
title: 'Additional Info',
icon: 'ti-location-pin',
component: 'step3'
},
{
title: 'Last step',
icon: 'ti-check',
component: 'step4'
},
],
}
},
methods: {
onComplete: function() {
alert('Yay. Done!');
},
validateStep(name) {
return this.$refs[name][0].validate()
},
mergeTabModel(model, isValid) {
if (isValid) {
// merging each step model into the final model
this.tabModel = Object.assign({}, this.tabModel, model)
}
}
}
})
<script src="https://vuejs.org/js/vue.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/vue-form-wizard/dist/vue-form-wizard.min.css">
<script src="https://unpkg.com/vue-form-wizard/dist/vue-form-wizard.js"></script>
<link rel="stylesheet" href="https://rawgit.com/lykmapipo/themify-icons/master/css/themify-icons.css">
<div id="app">
<div>
<form-wizard #on-complete="onComplete">
<wizard-step slot-scope="props" slot="step" :tab="props.tab" :transition="props.transition" :index="props.index">
</wizard-step>
<tab-content v-for="tab in tabs" v-if="!tab.hide" :key="tab.title" :title="tab.title" :icon="tab.icon" :before-change="()=>validateStep(tab.component)">
<component :is="tab.component" :ref="tab.component" #on-validate="mergeTabModel"></component>
</tab-content>
<template slot="footer" scope="props">
<div class="wizard-footer-left">
<!-- remove previous button -->
<!-- <wizard-button v-if="props.activeTabIndex > 0 && !props.isLastStep" #click.native="props.prevTab()" :style="props.fillButtonStyle">Previous</wizard-button> -->
</div>
<div class="wizard-footer-right">
<wizard-button #click.native="props.nextTab()" class="wizard-footer-right finish-button" :style="props.fillButtonStyle">{{props.isLastStep ? 'Done' : 'Next'}}</wizard-button>
</div>
</template>
</form-wizard>
<pre>{{ tabModel }}</pre>
</div>
</div>
using refs
this.$refs.wizardFirst.displayPrevButton = false
"vue-form-wizard": "0.8.4",
use this CSS instead:
.vue-form-wizard .wizard-nav-pills a, .vue-form-wizard .wizard-nav-pills li{
cursor: not-allowed;
pointer-events: none;
}
I have a button in vue component within template as follow:
<a href="#" #click="openTab" class="border-red px-8" id="activeSlide" data-target-quote="#yvoefrance">
<img :src="inactive_logo[0]" class="logo" alt="yvoefrance logo" />
</a>
I want it to be clicked by default when components loads after refreshing the page, how can I achieve this? I tried following but didn't work for me.
I thought the right place is created. Can anyone help? Thank you in advance.
export default {
name: "component.showcase",
components: {
// ...
},
data() {
return {
// data here....
};
},
created() {
document.querySelector("#activeSlide").click();
},
mounted() {},
beforeDestroy() {},
computed: {},
methods: {
openTab: function(e) {
e.preventDefault();
const target_tab = e.target.parentElement.dataset.targetQuote;
document.querySelector(target_tab).classList.add("active");
e.target.src = require(`#/assets/img/testimonials/${target_img}_active.png`);
}
}
};
The button should call a method when clicked:
<button #click="someMethod">Show Content</button>
Then you can just call that method programmatically from a lifecycle hook instead of trying to manually trigger a click on the button:
methods: {
someMethod() {
console.log('someMethod called');
}
},
created() {
this.someMethod(); // Run the button's method when created
}
EDIT to match your edit:
You are using DOM manipulation but should manipulate data instead and let Vue handle the DOM. Here is a basic example of how you can do what you want:
new Vue({
el: "#app",
data() {
return {
logos: [
{
urlInactive: 'https://via.placeholder.com/150/000000/FFFFFF',
urlActive: 'https://via.placeholder.com/150/FFFFFF/000000',
isActive: false
},
{
urlInactive: 'https://via.placeholder.com/150/666666/FFFFFF',
urlActive: 'https://via.placeholder.com/150/999999/000000',
isActive: false
}
]
}
},
methods: {
toggleActive(logo) {
logo.isActive = !logo.isActive;
}
},
});
<div id="app">
<a v-for="logo in logos" #click="toggleActive(logo)">
<img :src="logo.isActive ? logo.urlActive : logo.urlInactive" />
</a>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
I'm trying to get a method to execute on a parent component when a button in one of its child components is clicked. I am using single file components with Webpack. Here's the code for the child component:
<template>
<button v-on:click="add">Click</button>
</template>
<script>
export default {
methods: {
add: () => {
console.log('foo')
this.$dispatch('addClick')
}
}
}
</script>
And the code for the parent:
<template>
<div id="app">
<count :total="total"></count>
<click></click>
</div>
</template>
<script>
import count from './components/count.vue'
import click from './components/click.vue'
export default {
components: {
count,
click
},
data: () => {
return {
total: 0
}
},
methods: {
addToTotal: () => {
console.log('bar')
this.total += 1
}
},
events: {
addClick: 'addToTotal'
}
}
</script>
The count component is just an h1 element that displays the total variable. When I click the button, "foo" logs to the console, but "bar" does not and the total doesn't change. Any ideas on what I'm doing wrong? Thanks in advance!
You are using lambda notation for your methods, which is giving them the wrong this. If you use function instead, it will work.
Vue.component('click', {
template: '#clicker',
methods: {
add: function() {
console.log('foo')
this.$dispatch('addClick')
}
}
})
new Vue({
el: '#app',
data: () => {
return {
total: 0
}
},
methods: {
addToTotal: function () {
console.log('bar')
this.total += 1
}
},
events: {
addClick: 'addToTotal'
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script>
<template id="clicker">
<button v-on:click="add">Click</button>
</template>
<div id="app">
<count :total="total"></count>
<click></click>
{{total}}
</div>
Use two-way .sync binding type modifier on total property of count component so that the value will be updated when parent total value is changed. Here is an example:
Vue.component('click', {
template: '<button v-on:click="add">Click</button>',
methods: {
add: function () {
this.$dispatch('addClick');
}
}
});
Vue.component('count', {
template: '<h1 v-text="total"></h1>',
props: {
total: {
type: Number,
twoWay: true
}
}
});
new Vue({
el: '#app',
data: {
total: 1
},
methods: {
addTotal: function () {
this.total++;
}
},
events: {
addClick: 'addTotal'
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.25/vue.min.js"></script>
<div id="app">
<count :total.sync="total"></count>
<click></click>
</div>