Variable and method checking in Vue - vuejs2

One of the canonical examples on Vue website is:
<div id="app-5">
<p>{{ message }}</p>
<button v-on:click="reverseMessage">Reverse Message</button>
</div>
var app5 = new Vue({
el: '#app-5',
data: {
message: 'Hello Vue.js!'
},
methods: {
reverseMessage: function () {
this.message = this.message.split('').reverse().join('')
}
}
})
My problem is that if I rename the reverseMessage function, there is no error at compile time to notify me about this. Is there a way to receive an error at compile time when this happens?
Just a side note, although not really relevant: I am using Vue in conjunction with Typescript.
Thank you!

Related

Add new key for empty data object not working in Vuejs

I have question related to data of Vue.
I created data with an empty object.
data(){
return {
myObj: {}
}
}
and function like this:
methods: {
changeMyObj() {
this.myObj.newKey = 'aaaa';
}
}
Then I show it on template by click
<a #click="changeMyObj">Click change</a>
{{myObj.newKey}}
With this click, the nested key is not rendered on template. How can I resolve this issue?
Note: I do not meet this issue with Vuex or state of React.
This happens because of vue.js reactivity. In fact, here you are modifying a value that was not declared when the component mounted and Vue cannot track the changes.
You can update values by using the Vue.set method which allows Vue to track the data.
Vue.set(this.myObj, "myKey", "Hello world")
You can also make a deep copy of the object instead of just adding the key.
This can be done using the spread operator.
For example
this.myObj = {...this.myObj, myKey: "Hello world"}
Here is a small example using the two versions
new Vue({
el: "#app",
data: () => ({
myObj: {}
}),
methods: {
addKey(){
this.myObj = {...this.myObj, myKey: "Hello world foo"}
},
addKey2(){
Vue.set(this.myObj, "myKey", "Hello world bar")
},
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
{{ myObj.myKey }}
<button #click="addKey">Add key</button>
<button #click="addKey2">Add key 2</button>
</div>
I found the solution for this.
this.myObj = {...this.myObj, newKey:'aaaa'}
I do not think it is solution while it has no difference with:
this.myObj['newKey'] = 'aaaa';
or
this.myObj.newKey = 'aaaa';
If someone can explain why please let me know. Thanks
Correct way to assign a new property in an existing object is Vue.set(this.myObj, 'newKey', 'aaaa') to make it reactive instead of this.myObj.newKey = 'aaaa'
Demo :
new Vue({
el: '#app',
data: {
myObj: {}
},
methods: {
changeMyObj() {
Vue.set(this.myObj, 'newKey', 'aaaa')
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="changeMyObj">Click change</button>
{{ myObj.newKey }}
</div>

VueJs: bind `v-on` on a custom component to replace an existing one

In order to ease the styling of my page, I'd like to create a bunch of mini components like, and exploit how attributes are merged in VueJs. So for example, here is a minimal js file also hosted on this JSFiddle:
Vue.component('my-button', {
template: '<button style="font-size:20pt;"><slot></slot></button>'
})
var app = new Vue({
el: "#app",
data: {
message: "world",
},
methods: {
sayHello: function () {
alert("Hello");
}
}
})
and then in my html I just want to use <my-button> instead of button:
<div id="app">
Hello {{message}} <my-button #click="sayHello" style="color:red;">Style works, but not click</my-button> <button v-on:click="sayHello" style="color:red;">Both works</button>
</div>
Unfortunately, it seems that attributes are merged, but not listeners, so it means that I can't do v-on:click on my new button... Any way to make it possible?
Thanks!
-- EDIT --
I saw the proposition of Boussadjra Brahim of using .native, and it works, but then I found this link that explains why it's not a great practice and how to use v-on="$listeners" to map all listeners to a specific sub-button. However, I tried, to just change my template with:
template: `<button style="font-size:20pt;" v-on="$listeners"><slot></slot></button>`,
but I get an error:
Vue warn: Property or method "$listeners" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option."
Here is the JSFiddle.
Your fiddle didn't work because you were using an old version of Vue, $listeners was added in Vue 2.4.0.
Here's a demo:
Vue.component('my-button', {
template: '<button style="color: red" v-on="$listeners"><slot/></button>'
})
new Vue({
el: '#app',
methods: {
sayHello() {
alert('Hello')
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<my-button #click="sayHello">Custom Button</my-button>
<button #click="sayHello">Ordinary Button</button>
</div>

'Vue not defined' issue in combination with RequireJS

I have an issue where the Vue object is undefined in the browser, after I load in Vue with RequireJS. I'm not sure what's going on, I hope someone has some pointers to focus on.
Something worth noting is that I'm placing this code through our custom framework into a MVC C# application. Ultimately the code is placed in views and served along all other JS / HTML.
The HTML is placed first, after which the script is executed.
HTML:
<div id="aapje">
{{ message }}
</div>
JS:
require(['https://unpkg.com/vue'], function() {
var appje = new Vue({
el: '#aapje',
data: {
message: 'Hello Vue!'
}
});
});
Console dump:
Codepen: https://codepen.io/olafjuh/pen/oKWKXG
To achieve expected result, pass 'Vue' as parameter to callback funtion of require
working code sample
require(['https://unpkg.com/vue'], function(Vue) {
var appje = new Vue({
el: '#aapje',
data: {
message: 'Hello Vue!'
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.3/require.min.js"></script>
<div id="aapje">
{{ message }}
</div>
codepen - https://codepen.io/nagasai/pen/WVjVoV

VueJS - counter doesn't increase when I click the button

I'm learning VueJS with Maximilian Schwarzmüller in his VueJS course on Udemy and whenever I run his example on my local machine, it doesn't increase my counter variable.
<div id="app">
<button :click="increase">Click me</button>
<p>{{ counter }}</p>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
counter: 0
},
methods: {
increase() {
return this.counter++
}
}
})
</script>
Any idea what's wrong with the code?
Thanks a lot.
Data needs to be a function:
<script>
new Vue({
el: '#app',
data() {
return {
counter: 0
}
},
...
})
</script>
You have to use the # symbol for events, instead of : which is used for binding props.
<button #click="increase">Click me</button>
try this:
data: () => ({
counter: 0,
})
Your script will execute before your document is ready therefore Vue will not find your element to mount to.
Also as others already mentioned - your data property should be a function to make each instance with unique data object.
document.addEventListener('DOMContentLoaded', mountVue);
function mountVue() {
new Vue({
el: '#app',
data() {
return {
counter: 0
};
},
methods: {
increase() {
return this.counter++;
}
}
});
}
The problem was actually this:
<button :click="increase">Click me</button>
I was using the wrong short-hand syntax. I had to use the # sign (for events) instead.
<button #click="increase">Click me</button>
I was looking at this example here on CodePen and I noticed that their data object is not a function. Must the data object be a function? Are their benefits that I don't know about?
I'm very new to Vue right now and I'm learning from Max's course on Udemy. Thanks a lot.

Load default value from HTML input to vue.js data

I wonder if it is possible to load value of tag value as default value for vue.js data?
Works fine with
coupon: $('#coupon').val(),
but I really do not want to use jQuery.
Code is available here: https://jsfiddle.net/4a80dnfo/1/
So I found a way to get this done using the beforeMount() hook.
Assuming this HTML:
<div id="coupon-code">
<input ref="coupon" v-model="coupon" value="99PI_ORG" />
</div>
This Javascript should get the job done:
new Vue({
el: '#coupon-code',
data: {
coupon: ''
},
beforeMount: function() {
this.coupon = this.$el.querySelector('[ref="coupon"]').value;
}
// methods and such here.
}
});
I ended up using the beforeMount() hook after some trial an error. Some things I've learned which may be relevant:
this.$refs does not exist in the created() hook.
this.$refs.coupon.value returns an empty string in the mounted() hook.
The ref attribute of an element is deleted before the mounted() hook, so something like this.$el.querySelector('input[ref=coupon]') does not work.
You can use this.$el.querySelector('input[data-ref=coupon]').attributes['value'].value inside mounted(), but this seems worse to me than using beforeMount().
If anyone has suggestions on how to do this better, I'm very open to feedback. This solution still feels sub-optimal to me.
In your jsfiddle you are using v-model, so in your data() you just have to set your desired value
Edit: updated code to use v-bind
new Vue({
el: '#app',
data: {
coupon: 'You value here',
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.0/vue.js"></script>
<div id="app">
<input id="coupon" type="text" name="coupon" :value="coupon" />
</div>
<input name="coupon" v-model="coupon" value="def val">
window.app = new Vue({
el: '#xxx',
data: {
coupon: document.querySelector("input[name=coupon]").value
}
...
});