VueJS2 property not defined - javascript

I wrote the following code and Vue complains:
[Vue warn]: Property or method "incidents" is not defined on the
instance but referenced during render. Make sure to declare reactive
data properties in the data option.
I don't see why incidents cannot be accessed?
var app = new Vue({
el: '#app',
data: {
responders: [],
incidents: []
},
mounted: function () {
this.getIncidents();
},
methods: {
getIncidents: function() {
console.log('getIncidents');
var app = this;
this.$http.get('/api/v1/incidents').then(function(response) {
// set data
var incidentsReceived = response.data.map(function (incident) {
return incident;
});
Vue.set(app, 'incidents', incidentsReceived);
})
},
getResponders: function() {
console.log('fetchResponders');
var app = this;
this.$http.get('/api/v1/responders').then(function(response) {
// set data on vm
var respondersReceived = response.data.map(function (responder) {
return responder
});
Vue.set(app, 'responders', respondersReceived);
});
}
}
})

EDIT: Didn't read the code very well for the first time. Verify that you have data inside the response and if not don't set it the incidents array.

data is meant for internal component data modeling, while props, which can be assigned externally, are defined using the props key for your component.
In other words, try:
var app = new Vue({
...,
props: {
incidents: {
type: Array,
required: false //change this as you see fit.
}
},
...
});
For full documentation on component properties, please refer to the official guide.

Related

How to use data from one hook to other hook in Vue.js?

In my vue.js application I send request by axios package in created() hook. I add response to array called coordinates. I want to use that array outside of created() hook. For example in mounted() hook or in functions which we can set in methods.
Right now when I tried to use self.coordinates outside created() hook it return undefined. When I use this.coordinates it return just [__ob__: Observer].
Whats wrong I did?
export default {
name: "Map",
data() {
return {
coordinates: [],
}
},
created() {
let self = this;
axios.get('URL').then(function (response) {
let coordinates = [];
for (let i = 0; i < response.data.length; i++) {
coordinates.push([response.data[i]["LATITUDE"], response.data[i]["LONGITUDE"]]);
}
self.coordinates = coordinates;
});
},
mounted() {
console.log(self.coordinates); // undefined
consol.log(this.coordinates); // [__ob__: Observer]
},
}
I would prefer "mounted" and move the logic into methods for reusability. The method can be kicked from anywhere afterwards. In the example below, I prefered kicking the method direcly. Watchers is another option.
Here is the fiddle https://jsfiddle.net/dj79ux5t/2/
new Vue({
el: '#app',
data() {
return {
coordinates: []
}
},
mounted() {
let self = this;
axios.get('https://api.weather.gov/').then(function (response) {
self.coordinates = response.data;
self.greet();
});
},
methods: {
greet: function () {
console.warn(this.coordinates.status);
}
}
})
I think instead of mounted , you should use watch . You call some link so it will take time to load that data , watch method will trigger when your data is updated ...
watch: {
coordinates: {
handler: function (updateVal, oldVal) {
console.log(updateVal)
},
deep: true
}
},

Vue plugin, adding global component which takes data

I am using Vue plugins so that user can access a global component once registering the global component and configuring it inside Vue.use. For this I need to pass some data from Vue.use() to Component.vue.
Take a look at the following code:
Vue.use(MyPlugin, { data: true });
the code of MyPlugin is
import Plugin from './plugin';
const IconPlugin = {
install(Vue, options) {
console.log(options); // Here I can see {data: true}
Vue.component('GlobalComponent', Icon);
},
};
Now I need to pass this options variable to the component. So that a user whenever use
<GlobalComponent />
{data: true} should always be there.
Basically, that is a configuration which user is passing and the further component computation will be dependent on this.
You can use Vue.extend to extend components
var Icon = Vue.extend({
data: function() {
return {
foo: 'fooooo',
bar: 'barr'
}
},
template: '<div><button #click="doFooStuff">{{foo}}</button><button #click="doBarStuff">{{bar}}</button></div>',
methods: {
doBarStuff: function() {
console.log(this.foo, this.bar)
},
doFooStuff: function() {
console.log(this.foo)
}
}
})
const IconPlugin = {
install(Vue, options) {
// console.log(options);
// normalize data (select only props you want)
var data = Object.assign({}, options);
var NewIcon = Icon.extend({
data: function() {
return data;
}
})
Vue.component('GlobalComponent', NewIcon);
},
};
Vue.use(IconPlugin, {
foo: 'FOOO'
});
new Vue({
el: '#app',
components: {
Icon
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
<icon></icon>
<global-component></global-component>
</div>
it sounds like you want to take a look at the component guide. It would seem that you want to merge the data with where you are passing Icon.

Vue.js watching deep properties

I'm trying to watch properties on a vue.js object, but i'm not getting the result that i want, my code is the following:
var vueTable = new Vue({
el: '#vue-table',
data: {
filters: {},
},
watch: {
filters: {
handler: function () {
console.log('watched');
},
deep: true
}
}
}
And i have a v-model on an input like so:
<input class="form-control" v-model="filters.name">
Now when the page loads it logs watched in the console just once, whenever i change the input it doesn't log anything.
Yet when i put vueTable.filters = {name: 'something'}; after the table initalization it will trigger on every change.
Is this unexpected behaviour? or do we have to define all our properties in order for them to be watched?
The documentation covers this here.
Due to the limitations of modern JavaScript (and the abandonment of
Object.observe), Vue cannot detect property addition or deletion.
By starting with an empty object and setting v-model to filters.name, you end up adding a property dynamically. The best approach in this case would be to initialize the property in the data. It doesn't have to have a value.
data: {
filters: { name: null },
}
You can use something with the looks of this
this.$set(this.filters, 'name', "")
Using $set
(as described in https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats) the observable will be correctly added
You can put your filter object initialization in data property into the created Vue lifecycle hook.
var vueTable = new Vue({
el: '#vue-table',
// If you attach filters at this point in time
// the watcher will work normally.
created: function () {
this.$data.filters = {
filter_one: null,
filter_two: null
};
},
data: {
filters: null,
},
watch: {
filters: {
handler: function (newValue) {
// Here you will get the entire filter object
// if some property changes.
console.dir(newValue);
},
deep: true
}
}
}

Load new JSON data and replace the old one in VueJS

I'm using a v-for loop with data fetched from JSON file. Is there a way to re-render the DOM and whole v-for loop after loading a new JSON file and replacing the old one?
What I'm trying to achieve is load different sets of products on click and update DOM.
Vue.use(VueResource);
var productsList = new Vue({
el: '#vue',
data: function () {
return {
products: []
};
},
ready: function () {
this.$http.get('data/data.json').then(function (response) {
this.products = response.data;
});
},
methods: {
loadProducts: function (url) {
this.$http.get(url).then(function (response) {
this.products = response.data;
});
}
}
});
The code above should be sufficient for updating your DOM automatically. There are 2 errors however and 1 thing you should consider.
Anonymous functions have different scopes in javascript. This means that when you have an anonymous function function(response) then you lose the scope of the vue instance this. In order to deal with such situations you have to either use arrow functions if you have support for them in your project or save this into another variable before entering the anonymous function.
Vue.use(VueResource);
var productsList = new Vue({
el: '#vue',
data: function () {
return {
products: []
};
},
ready: function () {
var self=this;
this.$http.get('data/data.json').then(function (response) {
self.products = response.data;
});
},
methods: {
loadProducts: function (url) {
var self=this;
this.$http.get(url).then(function (response) {
self.products = response.data;
});
}
}
});
Also if you have this exact code, you should've received an error in browser with products being undefined.
Once you update the products data it will automatically change the DOM as par the latest data, as vue data is reactive. One error I see in your code is, you may have wrong this inside the this.$http block. instead of using function() syntax, use arrow function, which does not bind it's own this, arguments, super, or new.target, like following:
Vue.use(VueResource);
var productsList = new Vue({
el: '#vue',
data: function () {
return {
products: []
};
},
ready: function () {
this.$http.get('data/data.json').then((response) => {
this.products = response.data;
});
},
methods: {
loadProducts: function (url) {
this.$http.get(url).then( (response) => {
this.products = response.data;
});
}
}
});

set variable from component in instance

I want to set data variable of Vue instance from component. Is that even possible.
Vue.component('graph', {
template: '',
props: {},
data: function () {
methods: {
setBtn: function () {
//here i want to set ShowBtn variable for example to false
},
}, this.getUserRecordStatistic();
});
new Vue({
el: '#app',
data: {
showBtn: null
},
methods: {},
});
This should do the trick:
Vue.component('graph', {
template: '',
props: {},
data: {},
methods: {
setBtn: function () {
app.showBtn = false;
},
},
});
var app = new Vue({
el: '#app',
data: {
showBtn: null
},
methods: {},
});
You can access data on the root vue instance through vm.$root.
setBtn: function () {
this.$root.showBtn = false;
},
As a best practice you should avoid directly setting params on other components. Vue is intended to decouple its components therefore directly editing a param, although possible, runs in the face of this. Check out the components guide for more info, specifically: https://v2.vuejs.org/v2/guide/components.html#Composing-Components
Therefore rather than directly editing this param you should emit an event from the component which you can listen for on the root - or any other component that sets the graph component, i.e.
graph component emit an event
Vue.component('graph', {
methods: {
activateBtn () {
this.$emit('set-button', true)
},
...
root or any component that sets graph in its template
# template
<graph #set-button="setBtn"></graph>
# script
new Vue({
el: '#app',
data: {
showBtn: false
},
methods: {
setBtn (state) {
this.showBtn = state
},
},
})

Categories

Resources