I am trying to catch vue.js custom event within one component, but it's not catching. What's the problem?
myEventFunc: function() {
this.myEvent = true;
},
clickedFunc: function() {
this.clicked = true;
this.$emit('myevent');
}
JSFiddle Example: https://jsfiddle.net/ucean0rh/1/
I'm not sure if this is a Vue way of dealing with it, but it works in my JSFiddle. Simply call myEventFunc() from within clickedFunc:
new Vue({
el: "#app",
data: {
myEvent: false,
clicked: false,
},
methods: {
myEventFunc: function() {
this.myEvent = true;
},
clickedFunc: function() {
this.clicked = true;
this.myEventFunc();
this.$emit('myevent');
}
}
})
Related
I am creating undo/redo functionality in VueJS. I watch the settings and add a new element to an array of changes when the settings change. I also have a method for undo when the undo button is clicked.
However, when the button is clicked and the last setting is reverted, the settings are changed and the watch is fired again.
How can I prevent a new element being added to the array of changes if the settings changed but it was because the Undo button was clicked?
(function () {
var Admin = {};
Admin.init = function () {
};
var appData = {
settings: {
has_border: true,
leave_reviews: true,
has_questions: true
},
mutations: [],
mutationIndex: null,
undoDisabled: true,
redoDisabled: true
};
var app = new Vue({
el: '#app',
data: appData,
methods: {
undo: function() {
if (this.mutations[this.mutationIndex - 1]) {
let settings = JSON.parse(this.mutations[this.mutationIndex - 1]);
this.settings = settings;
this.mutationIndex = this.mutations.length - 1;
console.log (settings);
}
},
redo: function() {
}
},
computed: {
border_class: {
get: function () {
return this.settings.has_border ? ' rp-pwb' : ''
}
},
undo_class: {
get: function () {
return this.undoDisabled ? ' disabled' : ''
}
},
redo_class: {
get: function () {
return this.redoDisabled ? ' disabled' : ''
}
}
},
watch: {
undoDisabled: function () {
return this.mutations.length;
},
redoDisabled: function () {
return this.mutations.length;
},
settings: {
handler: function () {
let mutation = JSON.stringify(this.settings),
prevMutation = JSON.stringify(this.mutations[this.mutations.length-1]);
if (mutation !== prevMutation) {
this.mutations.push(mutation);
this.mutationIndex = this.mutations.length - 1;
this.undoDisabled = false;
}
},
deep: true
}
}
});
Admin.init();
})();
Since you make the changes with a button click, you can create a method to achieve your goal instead of using watchers.
methods: {
settings() {
// call this method from undo and redo methods if the conditions are met.
// move the watcher code here.
}
}
BTW,
If you don't use setter in computed properties, you don't need getters, so that is enough:
border_class() {
return this.settings.has_border ? ' rp-pwb' : ''
},
These watchers codes look belong to computed:
undoDisabled() {
return this.mutations.length;
},
redoDisabled() {
return this.mutations.length;
},
When reading Vue document
Non parent-child communication
For practice, I tried to build an example to see if it works, below is my code:
I build two component and tried to use Vue instance bus to transport message from dudi-station to dudo-station while on-click, but it's not working.
Can anyone help? Thanks!
Vue.component('dudi-station', {
template: '<div #click="sentMsg">{{dudiMsg}}</div>',
data: function() {
return {
dudiMsg: 'Dudi!!',
}
},
methods: {
sentMsg: function() {
bus.$emit('callout', this.dudiMsg);
},
}
});
Vue.component('dudo-station', {
template: '<div>{{dudoMsg}}</div>',
data: function() {
return {
dudoMsg:'',
}
},
created: function() {
bus.$on('callout', function(value) {
this.dudoMsg = value;
console.log(value);
});
}
});
var bus = new Vue();
new Vue({
el: '#app',
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<dudi-station></dudi-station>
<dudo-station></dudo-station>
</div>
Use arrow function as event handler when receiving message in component from another component. It will help you with "this" keyword scope.
bus.$on('callout', function(value) {
this.dudoMsg = value;
console.log(value);
});
instead of this use it as below
bus.$on('callout', (value) => {
this.dudoMsg = value;
console.log(value);
});
Because in this statement:
bus.$on('callout', function(value) {
this.dudoMsg = value;
this this is not mean your vue instance.
You need to use arrow function to make sure that 'this' means the vue instance.
Like below:
Vue.component('dudi-station', {
template: '<div #click="sentMsg">{{dudiMsg}}</div>',
data: function() {
return {
dudiMsg: 'Dudi!!',
}
},
methods: {
sentMsg: function() {
bus.$emit('callout', this.dudiMsg);
},
}
});
Vue.component('dudo-station', {
template: '<div>{{dudoMsg}}</div>',
data: function() {
return {
dudoMsg:'',
}
},
created: function() {
bus.$on('callout',value => {
this.dudoMsg = value;
console.log(value);
});
}
});
var bus = new Vue();
new Vue({
el: '#app',
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<dudi-station></dudi-station>
<dudo-station></dudo-station>
</div>
I am working on a FAQ page with vue.js
here is the example so far:
<li v-for="i in items | searchFor searchString"
v-on:click="toggleCollapse(i)"
:class="{ collapsed: i.collapse, expanded: !i.collapse }"
>
<p><strong>{{i.q}}</strong></p>
<p>{{i.a}}</p>
</li>
var vm = new Vue({
el: 'body',
data: {
items:[
{q:"test1", a:"a1", collapse:true},
{q:"test2", a:"a2", collapse:true},
{q:"test3", a:"a3", collapse:true},
{q:"test4", a:"a4", collapse:true},
{q:"test5", a:"a5", collapse:true},
{q:"test6", a:"a6", collapse:true}
]
},
methods: {
toggleCollapse: function(i) {
var self = this;
if(i.collapse){
self.items.forEach(function(a) {
a.collapse = true;
});
i.collapse = false;
}else{
i.collapse = true;
}
}
}
});
when user click on one of the items, the item will be expanded. The rest will be collapsed.
I want to call a jquery animation scrollTop function to scroll to the expanded item after users click.
I've tried vue instance such as watch, ready, mounted, updated etc but noe of them seems working.
Any ideas?
I found the solution, nextTick willdo:
methods: {
toggleCollapse: function(i) {
var self = this;
if(i.collapse){
self.items.forEach(function(a) {
a.collapse = true;
});
i.collapse = false;
}else{
i.collapse = true;
}
this.$nextTick(function(){
//command here
})
}
}
I have a vue component and a vue element declaration as given below
Vue.component('todo-item', {
template: '<li>This is a todo</li>'
methods: {
test: function() {
// I am getting an error here
app.aNewFunction();
}
}
})
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
},
methods: {
aNewFunction: function() {
alert("inside");
}
}
})
How to call a method in vue app from the vue component?
You can execute root instance method like this: this.$root.methodName()
Vue.component('todo-item', {
template: '<li>This is a todo</li>',
methods: {
test: function() {
this.$root.aNewFunction();
}
},
mounted() {
this.test();
}
})
new Vue({
el: '#app',
template: '<todo-item></todo-item>',
methods: {
aNewFunction: function() {
alert("inside");
}
}
})
Another solution which I think it's more accorded with Vuejs architecture, it's to use events listener & emitter between child-component and its parent to make communications.
Check this simple fiddle as a vision
Vue.component('todo-item', {
template: '<li>This is a todo</li>',
methods: {
test: function() {
console.log('Emmit this Event.');
this.$emit('yourevent');
}
},
created() {
this.test();
}
});
new Vue({
el: '#vue-app',
data: {
'message': '',
},
methods: {
aNewFunction(event) {
console.log('yourevent Is Triggered!');
this.message = 'Do Stuff...';
},
}
});
(New to Vue.js) I fetch data from a get request to display calendar information. I want this to update every 5 minutes.
Nothing in the docs about auto reload - how would I go about implementing this? Do I use standard javascript within the file or something else?
My complete app.js below:
Vue.component('events', {
template: '#events-template',
data: function() {
return {
list: []
}
},
created: function() {
this.fetchEventsList();
},
methods: {
fetchEventsList: function() {
this.$http.get('events', function(events) {
this.list = events;
}).bind(this);
}
}
});
new Vue({
el: 'body',
});
No need to re-invent the wheel, window.setInterval() does the job pretty well
Vue.component('events', {
template: '#events-template',
data () {
return {
list: [],
timer: ''
}
},
created () {
this.fetchEventsList();
this.timer = setInterval(this.fetchEventsList, 300000);
},
methods: {
fetchEventsList () {
this.$http.get('events', (events) => {
this.list = events;
}).bind(this);
},
cancelAutoUpdate () {
clearInterval(this.timer);
}
},
beforeUnmount () {
this.cancelAutoUpdate();
}
});
new Vue({
el: 'body',
});