i'm working on small project using Vue.js i have created a pagination system to display my database users in a table, i have a small issue, i would like to know how can i stop the setinterval if my getResult function page variable is bigger than 1.
this is my code :
data(){
return {
editMode : true,
customer_id : null,
laravelData : {},
formFields : {}
}
},
methods:{
getResults(page = 1){
axios.get('Thirdparty/loadCustomers/' + page).then(response => {
this.laravelData = response.data;
});
}
},
created(){
self = this;
setInterval(function(){
self.getResults();
}, 5000);
}
First and foremost, always capture identifiers from setInterval and setTimeout.
By capturing your interval ID you can later remove it from within your callback when the page value is larger than its default (1).
EDIT: The OP would like to be able to reset the interval when page resets.
created() {
this.resetInterval();
},
methods: {
resetInterval() {
this.currentInterval && clearInterval(this.currentInterval);
this.currentInterval = setInterval(() => this.getResults(), 5000);
},
getResults(page = 1) {
if (page == 1 && !this.currentInterval) {
this.resetInterval();
} else {
clearInterval(this.currentInterval);
}
axios.get('Thirdparty/loadCustomers/' + page).then(response => {
this.laravelData = response.data;
});
}
}
data(){
return {
editMode : true,
customer_id : null,
laravelData : {},
formFields : {},
currentInterval : null
}
},
methods:{
getResults(page = 1){
clearInterval(this.currentInterval);
axios.get('Thirdparty/loadCustomers/' + page).then(response => {
this.laravelData = response.data;
});
},
created(){
self = this;
self.currentInterval = setInterval(function(){
self.getResults();
}, 5000);
}
Related
So I have a vuetify simple table that displays available times to book appointments. However, this times are pull from a database and that information get changes every 5 minutes (based on people that booked or cancel). The user will need to refresh the table to get the latest changes. Im trying to introduce some sort of auto refresh in VueJs that reloads the data every 5 minuts. this is my method that is been called right now
created(){
this.fetchAvailableTimeSlotsData75();
},
method:{
fetchAvailableTimeSlotsData75() {
this.$axios.get('appointments75', {
params: {
date: this.isCurrentMonth(this.strSelectedDate) ? '' : this.strSelectedDate,
week: this.intPageNumber
}
})
.then((objResponse) => {
if(objResponse.status == 200){
// console.log(objResponse.data)
this.total = objResponse.data.total;
this.arrAvailableDates = objResponse.data.dates;
this.arrAppointmentsData = objResponse.data.data;
this.getAppointments();
}
})
.catch((objError) => {
})
.finally(() => {
this.blnLoading = false;
this.snackbar = false
});}
}
Whats the best way to approach this in VueJs? Any Ideas?
To put it simply, use setInterval:
var _timerId;
export default {
data: () => ({
pollingInterval: 1000 * 60 * 5
}),
created() {
this.startPolling(true);
},
methods: {
startPolling(init = false) {
if (init) {
// Call it immediately
this.fetchAvailableTimeSlotsData75();
this.startPolling();
return;
}
_timerId = setInterval(this.fetchAvailableTimeSlotsData75, this.pollingInterval);
}
},
// Optional
destroyed() {
clearInterval(_timerId);
}
}
I am creating undo/redo functionality in VueJS. I watch the settings and add a new element to an array of changes when the settings change. I also have a method for undo when the undo button is clicked.
However, when the button is clicked and the last setting is reverted, the settings are changed and the watch is fired again.
How can I prevent a new element being added to the array of changes if the settings changed but it was because the Undo button was clicked?
(function () {
var Admin = {};
Admin.init = function () {
};
var appData = {
settings: {
has_border: true,
leave_reviews: true,
has_questions: true
},
mutations: [],
mutationIndex: null,
undoDisabled: true,
redoDisabled: true
};
var app = new Vue({
el: '#app',
data: appData,
methods: {
undo: function() {
if (this.mutations[this.mutationIndex - 1]) {
let settings = JSON.parse(this.mutations[this.mutationIndex - 1]);
this.settings = settings;
this.mutationIndex = this.mutations.length - 1;
console.log (settings);
}
},
redo: function() {
}
},
computed: {
border_class: {
get: function () {
return this.settings.has_border ? ' rp-pwb' : ''
}
},
undo_class: {
get: function () {
return this.undoDisabled ? ' disabled' : ''
}
},
redo_class: {
get: function () {
return this.redoDisabled ? ' disabled' : ''
}
}
},
watch: {
undoDisabled: function () {
return this.mutations.length;
},
redoDisabled: function () {
return this.mutations.length;
},
settings: {
handler: function () {
let mutation = JSON.stringify(this.settings),
prevMutation = JSON.stringify(this.mutations[this.mutations.length-1]);
if (mutation !== prevMutation) {
this.mutations.push(mutation);
this.mutationIndex = this.mutations.length - 1;
this.undoDisabled = false;
}
},
deep: true
}
}
});
Admin.init();
})();
Since you make the changes with a button click, you can create a method to achieve your goal instead of using watchers.
methods: {
settings() {
// call this method from undo and redo methods if the conditions are met.
// move the watcher code here.
}
}
BTW,
If you don't use setter in computed properties, you don't need getters, so that is enough:
border_class() {
return this.settings.has_border ? ' rp-pwb' : ''
},
These watchers codes look belong to computed:
undoDisabled() {
return this.mutations.length;
},
redoDisabled() {
return this.mutations.length;
},
I tried components methods in vue js. My code like this.
const Thread = Vue.component('threadpage', function(resolve) {
$.get('templates/thread.html').done(function(template) {
resolve({
template: template,
data: function() {
return {
data: {
title: "Data Table",
count: this.GetData
}
};
},
methods: {
GetData: function() {
var data = {
username : "newshubid",
data : {
page : 0,
length : 10,
schedule : "desc"
}
};
var args = {"data" : JSON.stringify(data)};
var params = $.param(args);
var url = "http://example-url";
var result;
DoXhr(url, params, function(response){
result = JSON.parse(response).data;
console.log("load 1", result);
});
setTimeout(function () {
console.log("load 2", result);
return result;
}, 1000);
}
},
created: function(){
this.GetData();
}
});
});
});
But, when I trying to use {{ data.count }} in template. Not showing result what i want. Even I tried return result in GetData.
Whats my problem ? And how to access data from methods ? Please help me, i'm a beginner. Thanks
See the edited code and comments I added below.
You tried to return the result by using return in the function from setTimeout, which won't help you return value from GetData.
Instead, You can just set the value in the callback function of your ajax request.
const Thread = Vue.component('threadpage', function(resolve) {
$.get('templates/thread.html').done(function(template) {
resolve({
template: template,
data: function() {
return {
data: {
title: "Data Table",
// NOTE just set an init value to count, it will be refreshed when the function in "created" invoked.
count: /* this.GetData */ {}
}
};
},
methods: {
GetData: function() {
var data = {
username : "newshubid",
data : {
page : 0,
length : 10,
schedule : "desc"
}
};
var args = {"data" : JSON.stringify(data)};
var params = $.param(args);
var url = "http://example-url";
var result;
var vm = this;
DoXhr(url, params, function(response){
result = JSON.parse(response).data;
// NOTE set data.count to responsed result in callback function directly.
vm.data.count = result;
});
// NOTE I think you don't need code below anymore.
// setTimeout(function () {
// console.log("load 2", result);
// return result;
// }, 1000);
}
},
created: function(){
this.GetData();
}
});
});
});
Below is my code:
var CommonHeader = require('./header/CommonHeader.jsx');
var ListOptions = require('./header/ListOptions.jsx');
var SortableTable = require('../shared/SortableTable.jsx');
var ColumnDefinition = require('../shared/SortableTable/ColumnDefinition.jsx');
var DashboardApiActions = require('../../actions-api/DashboardApiActions');
var DashboardStore = require('../../stores/DashboardStore');
function constructList(data) {
var clickFunction = function(dashboardId, e) {
e.preventDefault();
DashboardApiActions.getDetail(dashboardId);
};
return data.map(function(row) {
return {
name : <a href="#" onClick={clickFunction.bind(this, row.id)}>{row.name}</a>,
createdBy : row.createdBy,
shared: "Share to everyone",
popularity: 20
};
});
}
function getState() {
return {
selectedTab: 'dashboard',
pageMetaData : DashboardStore.getPageMetaData(),
hasNextPage : DashboardStore.hasNextPage()
};
}
var List = React.createClass({
getInitialState: function() {
return getState();
},
handleDashboard: function() {
this.setState({
selectedTab: 'dashboard'
});
},
handleFav: function() {
this.setState({
selectedTab: 'fav'
});
},
handlePopular: function() {
this.setState({
selectedTab: 'popular'
});
},
wait: function(ms) {
alert('hi');
var start = new Date().getTime();
var end = start;
while(end < start + ms) {
end = new Date().getTime();
}
},
getDetails() {
var nextPageListener = this.state.hasNextPage ? this.handleNextPage : null;
if(this.state.selectedTab === 'dashboard') {
this.wait(1000);
var details = DashboardStore.getList();
console.log(details);
return (
<SortableTable data={constructList(details)} nextPageListener={nextPageListener} >
<ColumnDefinition dataField="name">Name</ColumnDefinition>
<ColumnDefinition dataField="createdBy">Owner</ColumnDefinition>
<ColumnDefinition dataField="shared">Shared With</ColumnDefinition>
<ColumnDefinition dataField="popularity">Popularity</ColumnDefinition>
</SortableTable>
);
} else if(this.state.selectedTab === 'fav') {
return(
<div className="col-md-12">
<span>Nothing to show</span>
</div>
);
} else if(this.state.selectedTab === 'popular') {
return(
<div className="col-md-12">
<span>Nothing to show</span>
</div>
);
}
},
_onChange : function() {
this.setState(getState());
},
componentDidMount : function() {
DashboardStore.addChangeListener(this._onChange);
},
componentWillUnmount : function() {
DashboardStore.removeChangeListener(this._onChange);
},
handleNextPage : function () {
var currPage = this.state.pageMetaData.pageNumber ? this.state.pageMetaData.pageNumber : 0;
DashboardApiActions.getDashboards(currPage + 1);
},
render: function(){
return(
<div id="dashboard">
<CommonHeader title={"Dashboard"} options={<ListOptions />}
handlePopular={this.handlePopular}
handleDashboard={this.handleDashboard}
handleFav={this.handleFav}/>
{this.getDetails()}
</div>
);
}
});
module.exports = List;
I have 3 tabs. On click of each I need to show some table data. On load My dashboard is selected. The issue is on load table is empty but if I click on some other tab and then again click on My dashboard tab then data is coming.
After debugging thoroughly I understood the problem is time issue, after 1000ms data is coming here -
var details = DashboardStore.getList();
so I called wait() to wait for 1000ms. Now one surprising thing is happening if I add one alert at wait() method then data is coming once I click on ok of alert box. If I remove the alert then on load data not coming anymore.
I checked API is hitting on load and response also coming.
so whats the issue. Please help me. I am stuck for a long time. :-(
It looks like the issue might be that you are using componentDidMount, there is some delay between this function being called and getInitialState so I suspect that you have a race condition between those 2.
Try using componentWillMount instead of componentDidMount.
Like so:
componentWillMount : function() {
DashboardStore.addChangeListener(this._onChange);
},
componentWillUnmount : function() {
DashboardStore.removeChangeListener(this._onChange);
},
So I created the following mixin:
var Polling = {
startPolling: function() {
var self = this;
setTimeout(function() {
self.poll();
if (!self.isMounted()) {
return;
}
self._timer = setInterval(self.poll(), 15000);
}, 1000);
},
poll: function() {
if (!this.isMounted()) {
return;
}
var self = this;
console.log('hello');
$.get(this.props.source, function(result) {
if (self.isMounted()) {
self.setState({
error: false,
error_message: '',
users: result
});
}
}).fail(function(response) {
self.setState({
error: true,
error_message: response.statusText
});
});
}
}
Note the console.log('hello'); in the poll function. I should see this every 15 seconds according to this logic.
Now lets look at a react component:
//= require ../../mixins/common/polling.js
//= require ../../mixins/common/state_handler.js
//= require ../../components/recent_signups/user_list.js
var RecentSignups = React.createClass({
mixins: [Polling, StateHandler],
getInitialState: function() {
return {
users: null,
error_message: '',
error: false
}
},
componentDidMount: function() {
this.startPolling();
},
componentWillUnmount: function() {
if (this._timer) {
clearInterval(this._timer);
this._timer = null;
}
},
shouldComponentUpdate: function(nextProps, nextState) {
if (this.state.users !== nextState.users ||
this.state.error !== nextState.error ||
this.state.error_message !== nextState.error_message) {
return true;
}
return false;
},
renderContents: function() {
if (this.state.users === null) {
return;
}
return (
<div>
<ul>
<UserList users={this.state.users} />
</ul>
</div>
);
},
render: function() {
return (
<div>
{this.loading()}
{this.errorMessage()}
{this.renderContents()}
</div>
)
}
});
RecentSignupsElement = document.getElementById("recent-signups");
if (RecentSignupsElement !== null) {
ReactDOM.render(
<RecentSignups source={ "http://" + location.hostname + "/api/v1/recent-signups/" } />,
RecentSignupsElement
);
}
Here we see in the componetDidMount function I am calling this.startPolling When the page loads, what I see after 1 second is:
hello
hello
A) its (poll fucntion) some how being called twice oO.
B) its (poll function) never being called again.
The reason I separated polling out is so that I can use it in other components on the same page and not duplicate code.
Very simply question(s):
Why and how do I fix this? I need it to poll ever 15 seconds and I should only see hello once when poll is called the first time.
On this line you call self.poll() and the result would be the timer:
self._timer = setInterval(self.poll(), 15000);
Instead pass the function:
self._timer = setInterval(self.poll, 15000);
As another option, in the spirit of "you're code's not working? just use someone else's instead!", react-async-poll is a handy component wrapper that you can use for polling.