Reference component in another one - vue.js

In a VueJS file i have two component :
var firstComponent = Vue.extend({
template: '#component1',
[...]
methods:
comp1function: function() {
[...]
comp2function()
}
[...]
}),
var secondComponent = Vue.extend({
template: '#component2',
[...]
methods:
comp2function: function(){
do things here
}
[...]
})
so what i want to do is to say : do comp2function when you finished to do comp1function. So is there any way i can reference a function from my template component2 in my template component1 ?

You should use Vue Events. I assume you are using VueJS 1.x?
So let's imagine you have those two components as you stated in your question:
var firstComponent = Vue.extend({
template: '#component1',
methods: {
doSomething () {
// Do things here
console.log('I do things')
// Fire an event when you want:
this.$dispatch('some-event')
}
}
})
var secondComponent = Vue.extend({
template: '#component2',
methods: {
doSomethingElse () {
console.log('I do something else')
}
},
events: {
trigger () {
this.doSomethingElse()
}
}
})
You need to trigger an event from your first component using the $dispatch method. Then, in your Vue Instance, you need to get that event, and use $broadcast to broadcast a new event to the other Vue children:
new Vue({
el: '#app',
components: {
firstComponent,
secondComponent
},
events: {
'some-event' () {
this.$broadcast('trigger')
}
}
})
You will then be able to get the event in your secondComponent and trigger whatever method you want
You can learn more about custom events on this page: http://v1.vuejs.org/guide/components.html#Parent-Child-Communication

Related

Vue watch not triggerring on elements in array

I have two components. One of them creates instances of the other one and adds them to an array then I try to watch on it to execute some functions, but it never triggers. My structure looks something like this:
const Child = Vue.extend({
data() {
triggerMe: false
},
methods: {
triggerSomething: function() {
console.log('It's called for sure');
this.triggerMe = true;
}
}
});
const Parent = Vue.extend({
data() {
children: []
},
components: {
child: Child
},
methods: {
addChild: function() {
this.children.push(new Child());
this.children[this.children.length - 1].$watch('triggerMe', _ => console.log('Never called'));
}
}
});
It works just right if it's the only one. How to fix that?
What I found is that $watch only triggers when component is mounted to some element in document. Other approach is needed:
<scipt id="parent-template">
<child
#trigger="triggerThat"
></child>
</script>
<script>
// in Child
this.$emit('trigger', someData);
// in Parent
methods: {
triggerThat: function(data) {
console.log('I can hear you');
console.log(data);
}
}
</script>

vuejs emit from a component of a component to the parent

I'm using a component2 in my component1. I want to emit a parent function from component2 but only component1 is called in parent.
At the moment I'm emit in component2 and listening in component1. Then emit in component1 again and listening in parent.
My current code:
// Emit the toggle-filter in component2
Vue.component('component2', {
template: `<div #click="$emit('toggle-filter')"></div>`
});
// Capture it in component1, the emit again
Vue.component('component1', {
template: `<div>
<component2 #toggle-filter="toggleFilter"></component2>
</div>`,
methods: {
toggleFilter () {
this.$emit('toggle-filter');
},
}
});
// At last, capture it in parent
new Vue({
el: '#filters',
template: `<div id="filters">
<component1 #toggle-filter="toggleFilter"></component1>
</div>`,
methods: {
toggleFilter () {
console.log('filter toggled');
}
}
});
What I want to achieve is something like below.
// Emit toggle-filter in component2
Vue.component('component2', {
template: `<div #click="$emit('toggle-filter')"></div>`
});
Vue.component('component1', {
template: `<div>
<component2></component2>
</div>`
});
// Then capture it in parent
new Vue({
el: '#filters',
template: `<div id="filters">
<component1 #toggle-filter="toggleFilter"></component1>
</div>`,
methods: {
toggleFilter () {
console.log('filter toggled');
}
}
});
Starting from Vue 2, methods related to cross-component communication has been removed, and it's recommended to centralise data and manage shared state using Vuex. If the example pattern occurs a lot in your app, consider to use Vuex instead.
Vue still allows to create an event hub and let components communicate through the hub globally. But remember that it's considered anti-pattern.
var eventHub = new Vue()
Vue.component('component2', {
template: `<div #click="toggleFilter"></div>`,
methods: {
toggleFilter() {
eventHub.$emit('toggle-filter')
}
}
});
Vue.component('component1', {
template: `<div><component2 ></component2></div>`
}
new Vue({
el: '#filters',
template: `<div id="filters"><component1></component1></div>`,
created() {
eventHub.$on('toggle-filter', this.toggleFilter)
},
beforeDestroy() {
eventHub.$off('toggle-filter', this.toggleFilter)
},
methods: {
toggleFilter () {
console.log('filter toggled');
}
}
});

How to destroy vuejs component from outside of component

I have created one of component in vuejs something like this
var tree_data = Vue.extend({
template: '#tree_data_template',
props: [
'groupmodal',
'search-name',
'tree-id'
], // props in single quotes
data: function () {
return {
shared: d2d.store
};
}
});
And use this component in another template like this.
var template_data = Vue.extend({
template: '#template_data',
created: function () {
var self = this;
self.shared.setCurrentRoute('templates');
},
components: {
'tree-data': tree_data
},
data: function () {
return {
id: this.$route.params.id,
shared: d2d.store,
};
},
methods: {
destroyComponent: function () {
//Need to code for destroy tree-data component
}
}
});
Blade file code
<tree-data
groupmodal="false"
search-name="user_search"
tree-id="user_tree"
>
</tree-data>
So finally how can i destroy my "tree-data" component through the "destroyComponent()" method
As cobaltway said you can use v-if
Setting v-if initially to false will render(generate) the component.
Then in your method setting v-if to true will destroy the component.
html
<div id="template_data">
<tree-data v-if="destroyComponent"></tree-data>
</div>
script
var template_data = Vue.extend({
template: '#template_data',
created: function () {
var self = this;
self.shared.setCurrentRoute('templates');
},
components: {
'tree-data': tree_data
},
data: function () {
return {
id: this.$route.params.id,
shared: d2d.store,
destroyComponent:true
};
},
methods: {
destroyComponent: function () {
//Need to code for destroy tree-data component
this.destroyComponent = false;
}
}
});
Here is the fiddle

Where I should place handler of emit?

I have child component and want to pass some data to it's parent.
My child component looks like:
// <button #click="sendClick($event)">Send</button>
// ...
data: function (){
return {
mycode: ""
}
},
methods: {
sendClick(e)
{
bus.$emit('change', this.mycode);
}
}
My parent component looks:
var app = new Vue({
el: '#app',
data: {
currentView: 'past-form',
mycode: ''
},
methods:
{
changeView()
{
this.currentView = 'past-form'
console.log(this.mycode);
},
},
created()
{
bus.$on('change', function(mycode){
this.mycode = mycode;
});
}
})
I haven't found a better place for placing bus.$on (bus is declared globally) than in created(), but the docs state that created() is for stuff that should be initialized after the page is loaded. The created() block works; I checked it by placing in it console.log(this.mycode), but should I move emit handler somewhere else?
It's look like my code does not execute mycode: '', because console.log(this.mycode); does not print anything.
As I mentioned in the comment, if your component is a direct child of your Vue, then there is no need for a bus.
That said, the created handler is fine for adding your bus event handler.
I expect the issue you have is a this issue. Try changing your handler to
bus.$on('change', mycode => this.mycode = mycode)
See How to access the correct this inside a callback?
Here is an example.
console.clear()
const bus = new Vue()
Vue.component("child", {
template: `<button #click="sendClick($event)">Send</button>`,
data: function() {
return {
mycode: "something"
}
},
methods: {
sendClick(e) {
bus.$emit('change', this.mycode);
}
}
})
var app = new Vue({
el: '#app',
data: {
currentView: 'past-form',
mycode: ''
},
methods: {
changeView() {
this.currentView = 'past-form'
console.log(this.mycode);
},
},
created() {
bus.$on('change', mycode => {
this.mycode = mycode
this.changeView()
})
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.js"></script>
<div id="app">
<child></child>
Parent mycode: {{mycode}}
</div>

Delegate event in vue

Im trying to delegate an avent from one instance to another.
I have a toolbar on the top of the page with a button like this
<div id="toolbar">
<button v-on:click="add" class="btn btn-default" type="submit"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Ny</button>
</div>
This add event working in this vue instance
var toolbarApp = new Vue({
el: '#toolbar',
data: {
},
methods: {
add: function (event) {
alert('lol');
}
}
});
But now i want to attach this add event to another instance like this
var contactApp = new Vue({
mixins: [toolbarApp],
el: '#contact',
data: {
showGrid: true,
showForm: false,
editMode: false
},
created: function () {
this.getContacts();
},
methods: {
getContacts: function () {
$.getJSON(this.apiGrid, function (data) {
this.contacts = data;
}.bind(this));
},
add: function (event) {
alert('hej');
}
}
});
But i cant attach this because of diffrent instance. Is it any way to do this?
Have also tried with mixedin with no luck.
Thanks in advice
what you are trying to do is not unique, there's even a title for it "Event bus"
EventBus = new Vue();
var toolbarApp = new Vue({
el: '#toolbar',
data: {
},
methods: {
add: function (event) {
EventBus.$emit('add-something', this.somevar);
}
}
});
then in your other instance:
var contactApp = new Vue({
mixins: [toolbarApp],
el: '#contact',
data: {
showGrid: true,
showForm: false,
editMode: false
},
created: function () {
this.getContacts();
EventBus.$on('add-something', function(somevar) {
// do cool stuff, like this.getContacts...
});
},
methods: {
getContacts: function () {
$.getJSON(this.apiGrid, function (data) {
this.contacts = data;
}.bind(this));
},
add: function (event) {
alert('hej');
}
}
});
Definition:
Sometimes you need a quick and easy solution to pass data between Vue.js components.
For an application with simple architecture it’s enough to communicate between components using events. For this we can create a quick solution and implement EventBus. EventBus allows us to emit an event in one component and listen for that event in another.
https://medium.com/#andrejsabrickis/https-medium-com-andrejsabrickis-create-simple-eventbus-to-communicate-between-vue-js-components-cdc11cd59860