VueJS on-click event not working - javascript

I couldn't manage to make it work. v-on:click event is not invoking the method on Vue instance. Here is the codes:
<div id="app">
<button class="btn btn-success" v-on:click="postEventData">
<i class="icon wb-share"></i> Publish
</button>
</div>
Vue instance:
var vm = new Vue({
el: '#app',
data: {
someData: 'fooBar'
},
methods: {
postEventData: function () {
axios.post('/foobar', vm._data);
}
}
});
Any help would be appreciated!

Change this axios.post('/foobar', vm._data);
to this: axios.post('/foobar', this.data);

I'm not seeing anything broken with your code.
That said, it would be better practice to use this to reference the Vue instance instead of vm. But, you would still need to reference the _data property of your Vue instance to get the data object (this.data is going to be undefined).
However, while you can reference your data object via this._data, it's a code smell. Your Vue instance's data properties are meant to be accessed individually directly off of this. Accessing the whole object breaks that paradigm.
If you are trying to submit { someData: 'fooBar' } in your post request, make a data property for that (say postData) and reference it via this.postData:
var vm = new Vue({
el: '#app',
data: {
postData: { someData: 'fooBar' }
},
methods: {
postEventData: function () {
axios.post('/foobar', this.postData);
}
}
});
Your template with v-on:click="postEventData" is fine.

Old question but this is what worked for me if someone else is stuck
button click event was actually trying to submit form since it was contained in a form element. So in order to make it call the method I had to do #click.prevent="myMethod()"
.prevent is the key. It acted as event.preventDefault()

Related

Declaring data in Vue with components

According to the docs, this is how you declare data in Vue:
data: {
name: 'Vue.js'
}
However, when I do that it doesn't work and an error shows in the console:
The "data" option should be a function that returns a per-instance value in component definitions.
I change it to the following and then it works fine:
data() {
return {
name: 'Vue.js',
}
}
Why do the Vue docs show the top bit of code when it doesn't work? Is there something wrong on my end?
Edit: This only happens when using components.
In a root Vue instance (which is constructed via new Vue({ . . . }), you can simply use data: { . . . } without any problems.
When you are planing to reuse Vue components using Vue.component(...) or using "template" tag, Use data attribute as a function.
Please review the corresponding section of the Vue.js documentation for more information regarding this problem
https://v2.vuejs.org/v2/guide/components.html#data-Must-Be-a-Function
You should declare data in Vue.js by doing
var app = new Vue({
el: '#app', //This is the container in which Vue will be in. The #app means the id of the container is app
data: {
}
});
It turns out you need to declare data in components different than when you set it on a Vue object.
Instead, a component’s data option must be a function, so that each instance can maintain an independent copy of the returned data object:
More: Vue docs

VueJS instance is being called even if the element is not on the page

I face an issue where all my VueJS instances are being called even if the element is not on the page.
I have a mixin declared like this.
var mixin = {
methods: {
listEvents(parameters) {
return axios.get('/api/v1/events', {params: parameters})
},
listLocations(parameters) {
return axios.get('/api/v1/locations', {params: parameters})
},
}
}
And multiple instances, that use this mixing. If you ask why multiple instances, it is because I use VuejS in multiple pages. For example, I have a page that is listing events and a page that is listing locations. So all my methods are in the mixin, and then the instance that is made for the page is called because the page contains the element specified in the instance (for example : id="locations" and el: "#locations")
Example of one instance :
// Vue
new Vue({
el: '#locations',
delimiters: ['[[', ']]'],
mixins: [mixin],
data: {
locations: [],
loading: true,
error: false,
page: 1,
perPage: 20,
},
mounted: function () {
console.log("VUEJS 'locations' has been mounted")
this.init();
},
methods: {
init() {
...
...
But, whatever the page I am on, all the instances are called... I can see all the API calls, the leaflet maps are initiated but there is no container, ... it is a mess.
Am I missing something or misunderstanding totally ?
EDIT : I may add that all instances are in app.js and this app.js is included in all pages.
It sounds like you have some script that is loaded on every page, instantiating new Vue objects, regardless of whether or not the elements those Vues attach to are rendered.
Vue will create instances even if the element you are instantiating it on does not exist.
That being the case, you could simply check to see if the elements exist before you create the Vue.
const locations = document.querySelector("#locations")
if (locations) {
new Vue({
el: "#locations",
...
})
}

Get script file outside of vue2 scope

I need to detect if adblocker is being used on my site, from googling around the most common method of checking this is to create a ads.js or adverts.js file and then display a message if that has been blocked.
This file has been set up however I am having trouble accessing this file when it needs to be outside of the vue scope in a vue componenet, any suggestions?
You might need to register independent js file's to the window object, then inside your component, you can call the object or function. For example, if your ads.js contain like as follow snippet
function block(){
// console.log('i am gonnna show this ')
}
In your vue component
var newData = new Vue({
el: '#app',
data: {
demo:'',
},
methods: {
fetchData: function (data) {
window.block()
}
},
created: function () {
window.block()
}
})
Like above the code you can achieve.

Where to use the main variable of a new vue instance

I'm obviously missing the point somewhere here, but where does one use the main variable of a new vue instance?
I'm new to vue.js (obviously) and whilst reading various documentation I can't help notice that each new vue instance starts with something like var app = new Vue({ but then in the examples I've read this app variable doesn't get referenced again in the js or html. The code works fine without referencing it anywhere.
Could someone please kindly advise on where or why I would use the app variable?
Many thanks
It's completely not required to capture the result of new Vue() if you don't need or want to.
The reason it's done is primarily for testing (ala from the console) or for interaction with external libraries. Because all of the methods and data of the Vue are available on the variable it's possible to call those methods and use that data from outside Vue.
For example, let's say I have some logic on my page completely outside Vue that has some data I want to use inside my Vue.
const externalData = {message:"I'm some interesting data."}
const myVueApp = new Vue({
el: "#app",
data:{
message: null
}
})
myVueApp.message = externalData.message
Here the code is setting the message property of Vue from outside Vue.
This is useful primarily when you have existing code, and you are integrating Vue into that existing environment.
Another scenario is just plain testing. Open your console and run the snippet below. Change the context to the snippet's javascript:
And then type
app.message = "Hey, this is nifty!"
And the new message will be reflected in the Vue.
console.clear()
const app = new Vue({
el: "#testing",
data:{
message: "Change me from the console!"
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="testing">
{{message}}
</div>

Javascript object data binding with Vue

I have a JavaScript object that I am attempting to bind to a Vue view.
I am running a function to update the JavaScript object using AJAX and I was expecting Vue to bind to the JS object and update the view when the object is updated though that isn't happening.
Research suggests making the AJAX call within the Vue declaration but due other constraits I would rather not do that.
I've created a fiddle to illustrate what the issue is since it's reproducable without the AJAX portion as well as pasted the code below.
https://jsfiddle.net/g6u2tph7/5/
Thanks in advance for your time and wisdom.
Thanks,
vmitchell85
JavaScript
window.changeTheData = function (){
externalJSSystems = [{description: 'Baz'}, {description: 'Car'}];
document.getElementById("log").innerHTML = 'function has ran...';
// This doesn't update the Vue data
}
var externalJSSystems = [{description: 'Foo'}, {description: 'Bar'}];
Vue.component('systable', {
template: '#sysTable-template',
data() {
return {
systems: externalJSSystems
};
}
});
new Vue({
el: 'body'
});
HTML
<systable :systems="systems"></systable>
<button type="button" onclick="changeTheData()">Change</button>
<br><br>
<div id="log"></div>
<template id="sysTable-template">
<table>
<thead>
<tr>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr v-for="sys in systems">
<td>{{ sys.description }}</td>
</tr>
</tbody>
</table>
</template>
Try this out :
externalJSSystems.push({description: 'Baz'}, {description: 'Car'});
It will append the new objects to externalJSSystems and the view will be updated. Why doesn't your example work ? Because you are assigning a new Array reference to externalJSSystems but Vue is still watching the old one.
To achieve what you want, don't assign a new Array instance but clear it. For example :
window.changeTheData = function (){
externalJSSystems.length = 0
externalJSSystems.push({description: 'Baz'}, {description: 'Car'});
}
When that instance of the systable Component is instantiated, Vue adds an "Observer" class to the initial externalJSSystems Array — extending the Array's prototype, adding getter/setters for each of the properties, and maintaining the two-way binding between the Component's data and the original Array. The changeTheData() method is overwriting that Vue-modified externalJSSystems Array with a completely new Array (that lacks the Observer), thus breaking the two-way binding.
In this way, externalJSSystems.push( … ) works because the default Array methods ('push', 'pop', 'shift', 'unshift', 'splice', 'sort', and 'reverse') have been mutated such that they are handled by the Observer.
I think the key to the behavior you're looking for lies in the Vue Component "props" — http://vuejs.org/guide/components.html#Props. In fact, it looks like your component markup — <systable :systems="systems"></systable> — is already set up to pass dynamic data to the Component instance. Right now, that :systems="systems" isn't doing anything. By defining systems in the Parent Vue scope, and defining systems as a prop(s) within the Component registration, you can pass dynamic data to Components within that Parent's scope.
Component
Vue.component('systable', {
template: '#sysTable-template',
props: {
systems: Array
}
});
Vue Instance
var vm = new Vue({
el: 'body',
data: {
systems: externalJSSystems
}
});
You can see it in action in this fiddle: https://jsfiddle.net/itopizarro/ycr12dgw/
I cached the Vue instance — var vm = new Vue({ … }) — so the changeTheData method had access to its systems data. This gives your external changeTheData() method a reference to the Vue instance where you defined system — thus giving it access to modify (without replacing, or iteratively adding/removing items from…) the Array of data.
Rather than making systems a data property, you can make it a computed property. Like the other answer said, the reference is to the old object. But if you make systems a computed property, it will automatically watch any variable used in the calculation (like externalJSSystems) and re-calculate the computed property.
Vue.component('systable', {
template: '#sysTable-template',
computed: {
systems() {
return externalJSSystems;
}
}
});

Categories

Resources