I am receiving data in JSON from PHP and I want to detect if JSON have changed on Javascript side, not template side. Does anybody have solution? I am attaching a code.
export default {
name: 'dashboard_invoices',
data() {
return {
invoices: [],
newInvoices: [],
}
},
methods: {
loadDataInterval: function() {
this.$http.get('http://127.0.0.1/pdaserwis-crm/api/vue/vue?action=order_table').then(function (response) {
this.newInvoices = response.data;
if(this.newInvoices != this.invoices) {
// alert('Dodano nowa fakture');
this.invoices = this.newInvoices;
}
})
},
loadData: function() {
this.$http.get('http://website.pl').then(function (response) {
this.invoices = response.data;
})
}
},
created: function () {
this.loadData();
setInterval(function () {
this.loadDataInterval();
}.bind(this), 3000);
}
}
I want to catch if invoices have changed and view appropriate alert for that.
The problem solved. It took to compare both arrays with deep-equal by watch handler.
watch: {
invoices: {
handler(val, oldVal)
{
if(!(deepEqual(val, oldVal))) {
console.log('elo');
}
}
}
}
Related
I am trying to setup a button that changes a data value in Vue but also have it set using localStorage initally. This way I can have it keep the previous state it was in before a page refresh. Below is the code I'm using and I'm able to get it to work but know that it would be preferable to use the computed section but haven't been able to get that to work properly.
Would anyone know what is going wrong?
My button is triggered using the testing method and the variable in question is isGrid.
export default {
data() {
return {
option: 'default',
}
},
components: {
FileUploader,
},
mixins: [
visibilitiesMixin,
settingsMixin
],
props: {
vehicleId: {
type: Number,
required: true,
default: null,
}
},
computed: {
...mapState([
'isLoading',
'images',
'fallbackImageChecks',
'selectedImages'
]),
isGrid: {
get() {
return localStorage.getItem('isGrid');
},
},
imagesVModel: {
get() {
return this.images;
},
set(images) {
this.setImages(images);
}
},
selectedImagesVModel: {
get() {
return this.selectedImages;
},
set(images) {
this.setSelectedImages(images);
}
},
removeBgEnabled() {
return this.setting('nexus_integration_removebg_enabled') === 'enabled';
},
},
mounted() {
this.loadImages(this.vehicleId);
},
methods: {
testing() {
if (this.isGrid === 'false' || this.isGrid === false) {
localStorage.setItem('isGrid', true);
this.isGrid = true;
console.log(this.isGrid);
console.log(localStorage.getItem('isGrid'));
} else {
localStorage.setItem('isGrid', false);
this.isGrid = false;
console.log('b');
console.log(this.isGrid);
console.log(localStorage.getItem('isGrid'));
}
},
}
I suggest you use vuex with vuex-persistedstate.
https://www.npmjs.com/package/vuex-persistedstate
I'm using vue in laravel and trying to get a controller function that I'm hitting to return the data so that I can use it in the data() section of my vue template.
I know the controller function returns what I need, but I'm not so sure how I need to handle the return/response in the axios call in order to start placing the data into the data() function in vue
Blade/Vue template
import moment from 'moment'
export default {
name: 'calendar',
data () {
return {
events: [
{
title: 'test',
allDay: true,
start: '2019-08-17',
},
],
config: {
defaultView: 'month',
eventRender: function(event, element) {
console.log(event)
}
},
}
},
created() {
this.fetchTasks();
},
methods: {
fetchTasks() {
axios.get('/landing/tasks' )
.then((response) => {
// handle success
this.assetOptions = response.data;
})
.catch(function (error) {
// handle error
console.log(error);
})
.finally(function () {
});
}
}
}
Route
Route::get('/landing/tasks', 'landingController#getTasks')
->name('landing/tasks');
Controller
public function getTasks()
{
$getTask = Task::getTaskForLanding();
$result = array();
foreach($getTask as $id => $task){
$result[$task->taskt_id][] = $task;
}
}
If you are certain that the Controller returns what you need, the only thing you are missing is declaration of assetOptions. To be able to assign response.data to assetOptions later on, you have to declare it in the data function first.
data() {
return {
...
assetOptions = []; // assuming you are expecting an array
...
};
}
Once that is done, you are all set.
I'm new to VueJs and currently trying to load some data only once and make it globally available to all vue components. What would be the best way to achieve this?
I'm a little bit stuck because the global variables occasionally seem to become null and I can't figure out why.
In my main.js I make three global Vue instance variables:
let globalData = new Vue({
data: {
$serviceDiscoveryUrl: 'http://localhost:40000/api/v1',
$serviceCollection: null,
$clientConfiguration: null
}
});
Vue.mixin({
computed: {
$serviceDiscoveryUrl: {
get: function () { return globalData.$data.$serviceDiscoveryUrl },
set: function (newUrl) { globalData.$data.$serviceDiscoveryUrl = newUrl; }
},
$serviceCollection: {
get: function () { return globalData.$data.$serviceCollection },
set: function (newCollection) { globalData.$data.$serviceCollection = newCollection; }
},
$clientConfiguration: {
get: function () { return globalData.$data.$clientConfiguration },
set: function (newConfiguration) { globalData.$data.$clientConfiguration = newConfiguration; }
}
}
})
and in my App.vue component I load all the data:
<script>
export default {
name: 'app',
data: function () {
return {
isLoading: true,
isError: false
};
},
methods: {
loadAllData: function () {
this.$axios.get(this.$serviceDiscoveryUrl)
.then(
response => {
this.$serviceCollection = response.data;
let configurationService = this.$serviceCollection.services.find(obj => obj.key == "ProcessConfigurationService");
this.$axios.get(configurationService.address + "/api/v1/clientConfiguration").then(
response2 => {
this.$clientConfiguration = response2.data;
}
);
this.isLoading = false;
})
}
},
created: function m() {
this.loadAllData();
}
}
</script>
But when I try to access the $clientConfiguration it seems to be null from time to time and I can't figure out why. For example when I try to build the navigation sidebar:
beforeMount: function () {
let $ = JQuery;
let clients = [];
if (this.$clientConfiguration === null)
console.error("client config is <null>");
$.each(this.$clientConfiguration, function (key, clientValue) {
let processes = [];
$.each(clientValue.processConfigurations, function (k, processValue) {
processes.push(
{
name: processValue.name,
url: '/process/' + processValue.id,
icon: 'fal fa-project-diagram'
});
});
clients.push(
{
name: clientValue.name,
url: '/client/' + clientValue.id,
icon: 'fal fa-building',
children: processes
});
});
this.nav.find(obj => obj.name == 'Processes').children = clients;
The most likely cause is that the null is just the initial value. Loading the data is asynchronous so you'll need to wait for loading to finish before trying to create any components that rely on that data.
You have an isLoading flag, which I would guess is your attempt to wait for loading to complete before showing any components (maybe via a suitable v-if). However, it currently only waits for the first request and not the second. So this:
this.$axios.get(configurationService.address + "/api/v1/clientConfiguration").then(
response2 => {
this.$clientConfiguration = response2.data;
}
);
this.isLoading = false;
would need to be:
this.$axios.get(configurationService.address + "/api/v1/clientConfiguration").then(
response2 => {
this.$clientConfiguration = response2.data;
this.isLoading = false;
}
);
If it isn't that initial value that's the problem then you need to figure out what is setting it to null. That should be prety easy, just put a debugger statement in your setter:
$clientConfiguration: {
get: function () { return globalData.$data.$clientConfiguration },
set: function (newConfiguration) {
if (!newConfiguration) {
debugger;
}
globalData.$data.$clientConfiguration = newConfiguration;
}
}
Beyond the problem with the null, if you're using Vue 2.6+ I would suggest taking a look at Vue.observable, which is a simpler way of creating a reactive object than creating a new Vue instance.
Personally I would probably implement all of this by putting a reactive object on Vue.prototype rather than using a global mixin. That assumes that you even need the object to be reactive, if you don't then this is all somewhat more complicated than it needs to be.
So I have the following code in one of my components:
export default {
name: 'section-details',
components: {
Loading
},
mounted() {
if (!this.lists.length || !this.section_types.length) {
this.$store.dispatch('section/fetch_section_form_data', () => {
if (this.section) {
this.populate_form();
}
});
}
else if (this.section) {
this.populate_form();
}
},
computed: {
section_types() {
return this.$store.state.section.section_types;
},
lists() {
return this.$store.state.list.lists;
},
loading() {
console.log(this.$store.state.section.loading);
this.$store.state.section.loading;
}
},
.
.
.
}
As you can see I have a computed property for "loading" that retrieves the attribute from my vuex store for when doing an ajax request.
in my section vuex module i have this:
fetch_section_form_data({ commit }, callback) {
commit("isLoading", true);
sectionService
.fetch_form_data()
.then((data) => {
commit("isLoading", false);
commit("fetch_section_types_success", data.section_types);
commit("list/fetch_lists_success", data.lists, { root: true});
if (callback) {
callback();
}
})
.catch((err) => {
commit("isLoading", false);
})
;
}
then in my mutations for the module i have the following code:
mutations: {
isLoading(state, status) {
state.loading = status;
},
}
Finally in my component where I store the loading property I have this:
<Loading v-if="loading"></Loading>
Anyways, for some reason the Loading component isn't showing up. the console.log in the loading() method however, is returning true for this.$store.state.section.loading. So for some reason Vue isn't picking up that loading == true in the actual DOM. Any help would be appreciated.
You need to return the value from the computed property method:
loading() {
return this.$store.state.section.loading;
}
I'm trying to access my data property in my Vue.js component. Looks like I'm missing something obvious.
Here is a short version of my code. StoreFilter.vue is a wrapper for matfish2/vue-tables-2.
<template>
<store-filter :selected.sync="storeIds"></store-filter>
</template>
<script>
import StoreFilter from './Filters/StoreFilter';
export default {
components: {
StoreFilter
},
data() {
return {
options : {
requestFunction(data) {
console.log(this.storeIds); //undefined
return axios.get('/api/orders', {
params: data
}).catch(function (e) {
this.dispatch('error', e);
}.bind(this));
},
},
storeIds: [],
}
},
watch : {
storeIds(storeIds) {
this.refreshTable();
}
},
methods : {
refreshTable() {
this.$refs.table.refresh();
}
}
}
</script>
How to get storeIds from requestFunction?
Use a closure, see rewrite below.
data() {
let dataHolder = {};
dataHolder.storeIds = [];
dataHolder.options = {
requestFunction(data) {
// closure
console.log(dataHolder.storeIds); // not undefined
return axios.get('/api/orders', {
params: data
}).catch(function (e) {
this.dispatch('error', e);
}.bind(this));
}
}
return dataHolder;
}
I recommend using the created() way to handle this.
export default {
// whatever you got here
data () {
return {
options: {}
}
},
created () {
axios.get('/api/orders', { some: params }).then(response => this.options = response.data)
}
}