Avoid adding reactive properties to a Vue instance or its root $data at runtime - declare it upfront in the data option. - laravel

I am a bit confused using VueJS2. I added a few variables to the data container for sending it to my API. That works fine but Vue is throwing me a warning/error message which I don't know how to solve:
Avoid adding reactive properties to a Vue instance or its root $data
at runtime - declare it upfront in the data option.
var app = new Vue({
el: '#app',
data: {
incidentReference: '',
streetName: '',
latitude: '',
longitude: '',
featureTypeId: 1,
archived: 0
},
computed: {
href() {
return '#' + this.name.toLowerCase().replace(/ /g, '-');
}
},
mounted: function () {
this.getIncidents();
},
methods: {
onSubmit() {
axios.post('/api/v1/incidents', this.$data)
.then(response => alert('Success'))
.catch(error => {
console.log(error.response);
})
},
getIncidents: function() {
console.log('getIncidents');
var self = this;
axios.get('/api/v1/incidents').then(function(response) {
// set data on vm
console.log(response.data);
var incidentsReceived = response.data.data.map(function (incident) {
return incident;
});
Vue.set(self, 'incidents', incidentsReceived);
});
}
}
});

You're creating a new reactive property on the response of your API
Vue.set(self, 'incidents', incidentsReceived);
Not sure if you misspelled property's name or forget to create that property. Just use an existing property on you data section
Vue.set(self, 'incidentReference', incidentsReceived); //change property name
or
data: {
incidents: null, //or create this property
},

In my case during unit testing using Jest, I was setting selected but didn't have on component so got this error.
wrapper.setData({
selected: recipients,
});
So created the property on component and then it's working fine.

In the context of Jest & Vue Test Utils consider declaring data in component:
const Component = {
// ..
data() { return { abc: 'abc'; } }
};
const wrapper = mount(Component, { /*..*/ });
instead of
const Component = { /*..*/ };
const wrapper = mount(Component, { /*..*/ });
wrapper.setData({ abc: 'abc' });
await wrapper.vm.$nextTick();

Related

issue with slowly geting data from api to vue view

I have issue with very slowly getting data from laravel api to vue view, I did tutorial where I have:
import axios from 'axios';
const client = axios.create({
baseURL: '/api',
});
export default {
all(params) {
return client.get('users', params);
},
find(id) {
return client.get(`users/${id}`);
},
update(id, data) {
return client.put(`users/${id}`, data);
},
delete(id) {
return client.delete(`users/${id}`);
},
};
<script>
import api from "../api/users";
export default {
data() {
return {
message: null,
loaded: false,
saving: false,
user: {
id: null,
name: "",
email: ""
}
};
},
methods: {
onDelete() {
this.saving = true;
api.delete(this.user.id).then(response => {
this.message = "User Deleted";
setTimeout(() => this.$router.push({ name: "users.index" }), 1000);
});
},
onSubmit(event) {
this.saving = true;
api
.update(this.user.id, {
name: this.user.name,
email: this.user.email
})
.then(response => {
this.message = "User updated";
setTimeout(() => (this.message = null), 10000);
this.user = response.data.data;
})
.catch(error => {
console.log(error);
})
.then(_ => (this.saving = false));
}
},
created() {
api.find(this.$route.params.id).then(response => {
this.loaded = true;
this.user = response.data.data;
});
}
};
</script>
It's load data from api very slowly I see firstly empty inputs in view and after some short time I see data, if I open api data from laravel I see data immediately, so my question is How speed up it? Or maby I did something wrong?
Whenever I am using an API with Vue, I usually make most of my API calls before opening the Vue then passing it in like this.
<vue-component :user="'{!! $user_data !!}'"></vue-component>
But if you have to do it in the Vue component, I am not sure if this will show improvement over your method but I would set it up with the "mounted" like so.
export default {
mounted() {
api.find(this.$route.params.id).then(response => {
this.loaded = true;
this.user = response.data.data;
});
}
}
Also heres a good tutorial on Axios and how to use HTTP Requets with Vue.
Hopefully this answered your question, good luck!

Gatsby - fetching remote images with createRemoteFileNode

I've been trying to fetch images from remote URL to Gatsby Source File system, to take advantage of lazy loading with gatsby-image plugin. I have a restful API which returns json with a string containing the image url. I followed this guide as I'm quite new to Gatsby Node Api and wasn't sure how to tackle this. Everything worked well until the point with adding additional properties to image with createNodeField. The properties seem to be added (I can see the object with fields property when I log the fileNode to the console. However, when trying to query the images, I get an error:
I'm wondering if there's something wrong in my code or is it due to the changes in gatsby? I'm using gatsby version 2.0.2. Is there a better option to somehow add additional properties to the image in order to be able to query just the needed ones?
Here's how my gatsby.node.js looks like:
const axios = require('axios');
const { createRemoteFileNode } = require(`gatsby-source-filesystem`);
exports.sourceNodes = ({ actions, createNodeId, node, store, cache } => {
const { createNode, createNodeField } = actions;
const processProject = project => {
project.photos.forEach(async photo => {
let fileNode;
try {
fileNode = await createRemoteFileNode({
url: photo.photo.url,
store,
cache,
createNode,
createNodeId: id => `projectPhoto-${photo.id}`,
});
await createNodeField({
node: fileNode,
name: 'ProjectPhoto',
value: 'true',
});
await createNodeField({
node: fileNode,
name: 'created_at',
value: photo.created_at,
});
} catch (error) {
console.warn('error creating node', error);
}
});
}
return axios.get(baseApiUrl).then(res => {
res.data.forEach(project => {
const nodeData = processProject(project);
createNode(nodeData);
});
});
}
In the end it seems that using .forEach with async/await was messing stuff up for some reason. Doing everything in for of loop, fixed the problem, although eslint was complaining about that a lot. Here's the code:
const axios = require('axios');
const { createRemoteFileNode } = require(`gatsby-source-filesystem`);
exports.sourceNodes = ({ actions, createNodeId, node, store, cache } => {
const { createNode, createNodeField } = actions;
const processProject = project => {
for (const photo of project.photos) {
let fileNode;
try {
fileNode = await createRemoteFileNode({
url: photo.photo.url,
store,
cache,
createNode,
createNodeId: id => `projectPhoto-${photo.id}`,
});
await createNodeField({
node: fileNode,
name: 'ProjectPhoto',
value: 'true',
});
await createNodeField({
node: fileNode,
name: 'created_at',
value: photo.created_at,
});
} catch (error) {
console.warn('error creating node', error);
}
}
}
return axios.get(baseApiUrl).then(res => {
res.data.forEach(project => {
const nodeData = processProject(project);
createNode(nodeData);
});
});
}

Vuejs function with multiple data

I have two data table in vue app.
Cash [code, description,cash]
Upload [bank, id]
For my update function, i need to take [bank, id] from upload and [cash] from cash. i don't know how, can someone help please ? Thank you. This is my code
This is my vuejs
var app = new Vue({
el: '#app',
data: {
cash: {
codeentry: '',
description: '',
cash: '',
},
upload: {
bank: '',
id: '',
},
},
methods: {
updateBank: function () {
axios.put('/updatebank', this.upload, this.cash)
.then(response => {
if (response.data.etat) {
this.upload.id = response.data.etat.id
this.upload.bank = response.data.etat.bank
this.cash.cash = response.data.etat.cash
}
})
.catch(error => {
console.log('errors: ', error)
})
},
}
});
My route :
Route::put('/updatebank', 'CoinController#updateBank');
Controller :
public function updateBank(Request $request)
{
$coin = Coin::findOrFail($request->id);
$coin->bank = ($request->bank - $request->cash);
$coin->save();
}
When i execute my function and see the report. Only this.upload is token in consideration.
If you mean to have the two data in one object, you can make a new object from the two objects
Es6 Example:
const {bank,id} = this.upload;
const {cash} = this.cash;
const my_data = {
bank, id, cash
}
Older Js example
var my_data = {
cash: this.cash.cash,
bank: this.upload.bank,
id: this.upload.id,
}
Otherwise, if you want to have both in the request as separate objects then wrap around them {}
var my_data = {
upload: this.upload,
cash: this.cash
}
Finally:
axios.put('/updatebank', my_data)
...
Update: It appears you don't want to merge those objects as different sub-object so your updateBank method would be like so:
updateBank: function () {
const my_data = {
cash: this.cash.cash,
bank: this.upload.bank,
id: this.upload.id,
};
axios.put('/updatebank', my_data)
.then(response => {
if (response.data.etat) {
this.upload.id = response.data.etat.id
this.upload.bank = response.data.etat.bank
this.cash.cash = response.data.etat.cash
}
})
.catch(error => {
console.log('errors: ', error)
});
}
Just a side observation, are you sure the this in the response references your Vue object?

Error TypeError: Cannot read property 'dispatch' of undefined at app.js:12012

Hi I've been trying to learn vuejs and vuex while trying to get response from an api call with vuex concept I got the following error.Please help.
This error occurred
Error TypeError: Cannot read property 'dispatch' of undefined
at app.js:12012
loginAction.js
export const getUsersList = function (store) {
let url = '/Apis/allUsers';
Vue.http.get(url).then((response) => {
store.dispatch('GET_USER_RES', response.data);
if (response.status == 200) {
}
}).catch((response) => {
console.log('Error', response)
})
}
loginStore.js
const state = {
userResponse: []
}
const mutations = {
GET_USER_RES (state, userResponse) {
state.userResponse = userResponse;
}
}
export default {
state, mutations
}
login.vue
import {getUsersList} from './loginAction';
export default {
created () {
try{
getUsersList();
}catch(e){
console.log(e);
}
},
vuex: {
getters: {
getUsersList: state => state.userResponse
},
actions: {
getUsersList
}
}
}
</ script>
If you call the actions manually (like in your try/catch) they'll not get the store context as the first argument. You could use getUsersList(this.store) I think, but instead I would use dispatch to reach all your actions. (I edited just a little bit to get a minimal running example, but I think you get the point!)
new Vue({
render: h => h(App),
created() {
this.$store.dispatch('getUsersList');
},
store: new Vuex.Store({
getters: {
getUsersList: state => state.userResponse
},
actions: {
getUsersList
}
})
}).$mount("#app");
Also, use commit to reach the mutations instead of dispatch. ie:
export const getUsersList = function ({commit}) {
let url = '/Apis/allUsers';
Vue.http.get(url).then((response) => {
commit('GET_USER_RES', response.data); // because GET_USER_RES is a mutation
...

Redux action ajax result not dispatched to reducer

I just get to experiment with Redux and I know that middleware is essential to make ajax calls. I've installed redux-thunk and axios package separately and tried to hook my result as a state and render the ajax result to my component. However my browser console displays an error and my reducer couldn't grab the payload.
The error:
Uncaught Error: Actions must be plain objects. Use custom middleware for async actions.
This is part of my code and how the middleware is hooked up:
//after imports
const logger = createLogger({
level: 'info',
collapsed: true,
});
const router = routerMiddleware(hashHistory);
const enhancer = compose(
applyMiddleware(thunk, router, logger),
DevTools.instrument(),
persistState(
window.location.href.match(
/[?&]debug_session=([^&]+)\b/
)
)
// store config here...
my action:
import axios from 'axios';
export const SAVE_SETTINGS = 'SAVE_SETTINGS';
const url = 'https://hidden.map.geturl/?with=params';
const request = axios.get(url);
export function saveSettings(form = {inputFrom: null, inputTo: null}) {
return (dispatch) => {
dispatch(request
.then((response) => {
const alternatives = response.data.alternatives;
var routes = [];
for (const alt of alternatives) {
const routeName = alt.response.routeName;
const r = alt.response.results;
var totalTime = 0;
var totalDistance = 0;
var hasToll = false;
// I have some logic to loop through r and reduce to 3 variables
routes.push({
totalTime: totalTime / 60,
totalDistance: totalDistance / 1000,
hasToll: hasToll
});
}
dispatch({
type: SAVE_SETTINGS,
payload: { form: form, routes: routes }
});
})
);
}
}
reducer:
import { SAVE_SETTINGS } from '../actions/configure';
const initialState = { form: {configured: false, inputFrom: null, inputTo: null}, routes: [] };
export default function configure(state = initialState, action) {
switch (action.type) {
case SAVE_SETTINGS:
return state;
default:
return state;
}
}
you can see the state routes has size of 0 but the action payload has array of 3.
Really appreciate any help, thanks.
It looks like you have an unnecessary dispatch in your action, and your request doesn't look to be instantiated in the correct place. I believe your action should be:
export function saveSettings(form = { inputFrom: null, inputTo: null }) {
return (dispatch) => {
axios.get(url).then((response) => {
...
dispatch({
type: SAVE_SETTINGS,
payload: { form: form, routes: routes }
});
});
};
}

Resources