Vue render button - javascript

My question is about render a button on vue instance, to click in a button and then it render another button with event click, If I simple mount the button it dont get the function tes.
const Hello = {
props: ['text'],
template: '<button v-on:click="tes"> </button> ',
};
new Vue({
el: '#app',
data: {
message: 'Click me'
},
methods:{
alertar: function(event){
const HelloCtor = Vue.extend(Hello);
var instance = new HelloCtor({
propsData: {
text: 'HI :)'
}
})
instance.$mount() // pass nothing
this.appendChild(instance.$el)
},
tes: function(){
alert('Teste');
}
}
})
Erro :
vue.js:597 [Vue warn]: Invalid handler for event "click": got undefined
(found in <Root>)
warn # vue.js:597
(index):52 Uncaught TypeError: this.appendChild is not a function
at Vue.alertar ((index):52)
at invoker (vue.js:2029)
at HTMLParagraphElement.fn._withTask.fn._withTas

The problem is that you create a child component inside of your parent Vue that contains the template with the binding to the tes function. That means that the child will look in its own methods for tes, however it is a property of your parent, not of the child itself so it will never be able to find it in its own scope. You have to add the function to the child component instead:
const Hello = {
props: ['text'],
template: '<button v-on:click="tes"> </button> ',
methods: {
tes: function(){
alert('Teste');
}
}
};

Just expanding #Philip answer
Basically you can't access parent methods in programatically created components.
You need to specify the methods inside the child components.
const Hello = {
props: ['text'],
template: '<button v-on:click="this.tes"> Vue Generated</button> ',
methods: {
tes: function(){
alert('Teste');
}}
};
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
},
mounted(){
this.alertar()
},
methods:{
alertar: function(event){
const HelloCtor = Vue.extend(Hello);
var instance = new HelloCtor({
propsData: {
text: 'HI :)'
}
})
instance.$mount() // pass nothing
this.$refs.container.appendChild(instance.$el)
},
tes: function(){
alert('Teste');
}
}
})
Check this fiddle here
https://jsfiddle.net/50wL7mdz/370645/
However in some cases you may be able to access the parent components methods using
$parent directive which I believe will not work when components is created programatically.

Related

Vue.js method is not defined

Here is some problem with methods,
my component can't access to methods. May i need to pass methods like prop to component ?
here is my html:
<guests v-bind="guests"></guests>
here is component in my js file
var guestsComponent = Vue.component("guests", {
props: ['adultCount', 'childCount'],
template: `
<div class="guests-total">
<div>
<a #click="decrementAdult"></a>
<a #click="incrementAdult"></a>
<input type="text" placeholder="adults"/> {{adultCount}}
</div>
</div>
`
});
and here in the same js file my vue init and methods
var app = new Vue({
el: "#search",
components: {
"guests": guestsComponent
},
data() {
return {
guests: {
adultCount: 0,
childCount: 0
}
};
},
methods: {
decrementAdult() {
this.guests.adultCount++
},
incrementAdult() {
this.guests.adultCount--
}
}
});
I can access to data without problem when i use the props but i don't know how i can pass methods like props or this is needed?
here is error on console:
ReferenceError: decrementAdult is not defined
at o.eval (eval at xa (vue.min.js:NaN), <anonymous>:3:88)
at o.fn._render (vue.min.js?f6b5:6)
at o.eval (vue.min.js?f6b5:6)
at St.get (vue.min.js?f6b5:6)
at new St (vue.min.js?f6b5:6)
at o.hn.$mount (vue.min.js?f6b5:6)
at o.hn.$mount (vue.min.js?f6b5:6)
at init (vue.min.js?f6b5:6)
at eval (vue.min.js?f6b5:6)
at b (vue.min.js?f6b5:6)
Since the click events are done in the child component guests you should emit an event to the parent component and handle it there like :
....
<a #click="$emit('decrement-adult')"></a>
...
in the parent component do :
<guests v-bind="guests" #decrement-adult="decrementAdult"></guests>
I ran into a similar 'method1' is not defined error from the following code section:
methods: {
method1(){
console.log("running method1()");
},
method2(){
method1();
},
...
The problem was that the reference to method1() should have included the this keyword like so:
export default {
name: 'TuringMachine',
props: {
msg: String,
},
data() {
},
methods: {
method1(){
console.log("running method1()");
},
method2(){
this.method1();
}
}
}
Hope this helps anyone with the same issue.

Vue- variables inside event bus are not reactive

I created global event bus
Vue.prototype.$eventHub = new Vue()
In 'component 2' clicking on the button, emitted the event then navigating to 'component 1'
this.$eventHub.$emit('deleted')
In another 'component 1' i am trying to use it
data: function () {
return {
testVariable : true
}
},
beforeMount () {
var self = this
this.$eventHub.$on('deleted', function () {
console.log("executed")
self.testVariable = false
})
}
In the template section i used {{testVariable}}, it's always displaying true. Why it is not reactive? what did i miss?

Vue watcher executed before the new data is bound?

I am using this code:
var vueApp = new Vue({
el: '#app',
data: {
modalKanji: {}
},
methods: {
showModalKanji(character) {
sendAjax('GET', '/api/Dictionary/GetKanji?character=' + character, function (res) { vueApp.modalKanji = JSON.parse(res); });
}
},
watch: {
'modalKanji': function (newData) {
setTimeout(function () {
uglipop({
class: 'modalKanji', //styling class for Modal
source: 'div',
content: 'divModalKanji'
});
}, 1000);
}
}
});
and I have an element that when clicked on, displays a popup with the kanji data inside:
<span #click="showModalKanji(kebChar)" style="cursor:pointer;>
{{kebChar}}
</span>
<div id="divModalKanji" style='display:none;'>
<div v-if="typeof(modalKanji.Result) !== 'undefined'">
{{ modalKanji.Result.literal }}
</div>
</div>
It works, but only when used with a setTimeout delay to "let the time for Vue to update its model"...if I remove the setTimeout so the code is called instantaneousely in the watch function, the popup data is always "1 iteration behind", it's showing the info of the previous kanji I clicked...
Is there a way for a watcher function to be called AFTER Vue has completed is binding with the new data?
I think you need nextTick, see Async-Update-Queue
watch: {
'modalKanji': function (newData) {
this.$nextTick(function () {
uglipop({
class: 'modalKanji', //styling class for Modal
source: 'div',
content: 'divModalKanji'
});
});
}
}

vuejs - remount after update background url

I have a vue component with the binding style:
<div id="profile-icon" :style="{'background': 'url('+profile.icon+')'}"></div>
<input name="name" v-model="profile.name" type="text" placeholder="Name">
The image will only display if I update the profile.icon under beforeMount function:
props: ['profileprops'],
data: function() {
return {
profile: {
address:'',
name:'Name',
description:'Short description',
address:'address',
user_id:'',
background:'/images/admin/bg.png',
icon:''
},
}
},
beforeMount: function() {
console.log('profileedit mounted.')
var self = this;
if(self.profileprops){
self.profile = self.profileprops;
};
if(!self.profile.icon){
self.profile.icon = '/images/admin/icon-144.png';
},
mounted: function() {
var self = this;
self.$eventHub.$on('ImageSelected', (imagelink) => {///<-- I have another vue component for selecting images to emit event and to catch it here.
self.profile.icon = imagelink;
$('#profilemodal').modal('hide');
});
},
watch: {
'profile': {
handler: function(newVal, oldVal) {
console.log("changed")
},
deep: true
},
}
I did a few tests:
if I select the image, I can see the console.log within the $on has given the correct data from profile.icon. However, the :style did not update the background image with the new profile.icon. And watch.profile did not react at all.
If I start to type on input with v-model bind with profile.name, everything update immediately, including the background image in :style.
I believe I must have miss something to sync the inside and outside of the $on. How can I resolve this?
I found the solution here.
So I just $forceUpdate() inside $on:
self.$eventHub.$on('ImageSelected', (imagelink) => {
self.profile.icon = imagelink;
self.$forceUpdate();//<-- this does the magic.
});
then the data will update and re-render.

VueJs 2 emit custom event firing, but not being "heard"

Probably not possible, but I have an object that extends Vue/ VueComponent (tried both) that $emits a custom event that would normally be caught on its parent.
Please see this pen: https://codepen.io/anon/pen/MvmeQp?editors=0011 and watch the console.
class nonVueComponent extends Vue {
constructor(age,...args){
super(args)
console.log('new Blank Obj')
setTimeout(() => {
console.log('customEvent event does fire, but nothing hears it. Probably because it isnt in the DOM?', age)
this.$emit('customEvent', `custom event from nonVueComponent...${age}`)
},500)
}
}
Vue.component('test', {
template: `<div>
{{content}}
<child :childAge="age" #customEvent="customEvent"></child>
<child-secondary #secondaryEvent="customEvent"></child-secondary>
</div>`,
props: {},
data () {
return {
content: 'hello from component!',
age : 20
}
},
methods : {
customEvent(data){
console.log('PARENT: custom event triggered!', data)
this.content = data
},
secondaryEvent(data){
console.log('PARENT: !!secondary custom event triggered', data)
this.content = data
}
}
})
Vue.component('child',{
template: `<div>+- child {{childAge}}</div>`,
props: ['childAge'],
data () {
outsideOfVue: new nonVueComponent(this.childAge)
}
})
Vue.component('child-secondary',{
template: `<div>+- secondary event</div>`,
mounted(){
setTimeout( ()=>{
this.$emit('secondaryEvent', 'from secondary event....')
},125 )
}
})
let vm = new Vue({ el: '#app'})
Aside from using an eventBus, is there any other way to get the event up and out from the <child> ? Maybe make the nonVueComponent a mixin?
Thanks.
code:https://codepen.io/anon/pen/EvmmKa?editors=0011
The object who emits the event should be the instace of child-secondary.
Try to convey the instance to the nonVueComponent's constructor.
class nonVueComponent extends Vue {
constructor(age,comp,...args){
super(args)
console.log('new Blank Obj')
setTimeout(() => {
console.log('customEvent event does fire, but nothing hears it. Probably because it isnt in the DOM?', age)
comp.$emit('customEvent', `custom event from nonVueComponent...${age}`)
},500)
}
}

Categories

Resources