Reload HTML elements with javascript not working - javascript

I get a list of items and use it to dynamically create an HTML list
_loadList(){
HttpUtils.get('http://myserver/list/users/')
.then((res) => {
const self = this;
res.forEach((item) => {
userListContainer.append('<li> item.name </li>')
});
});
}
I call this function in the constructor, everything is working fine
constructor() {
this._loadList();
}
I am trying to recall this function every 5 seconds to update the list with the new result:
constructor() {
const that = this;
this._loadList();
window.setInterval(function(){
that._loadList();
}, 5000);
}
The function is called, the received result contains the new content, but the HTML is not updated. Do you have an idea about the problem?

You can try below code that will work for in your case. You can checkout https://es6console.com/jgyxgm1f/ example which will alert random number (in your case it's equivalent of adding new data coming from API response).
_loadList = () => {
HttpUtils.get('http://myserver/list/users/')
.then((res) => {
userListContainer.empty();
res.forEach((item) => {
userListContainer.append('<li> item.name </li>')
});
});
}
constructor = () => {
this._loadList();
window.setInterval(() => {
this._loadList();
}, 5000);
}

Related

VueJs do a reload on a simple table from Vuetify

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);
}
}

How to handle only one observer and dont call others?

I have the following usage of rxjs streams:
ngOnInit() {
combineLatest(
this.eventsService.subjectSearchDistribution.pipe(
tap((querySearch) => {
this.paginationService.setQuery(querySearch);
this.paginationService.reset();
}),
),
this.eventsService.subjectSortingDistribution.pipe(
tap((sortedList: ListItem[]) => {
this.paginationService.setSortBy(getSortingString(sortedList));
}),
),
this.eventsService.subjectFilterDistribution.pipe(
tap((filterUrl) => {
const page = 1;
this.paginationService.setFilterBy(filterUrl);
this.paginationService.setCurrentPage(page);
this.paginationService.calculateOffsetLimit(page);
}),
),
this.eventsService.subjectFilterDistributionReset.pipe(tap(() => this.paginationService.reset())),
).subscribe(() => {
this.loadPage();
});
}
Problem is I need to handle only one case, onle one stream and dont call others, as result call this.loadPage();.
Now when I send message to this.eventsService.subjectSearchDistribution, this.eventsService.subjectSortingDistribution, this.eventsService.subjectFilterDistribution.
I see that calling of this.loadPage(); increases from fist time +1 each event.
SO, ONLY one observer can be active, not all torgether.
How to fix it?
It seems the reason your loadPage method is called twice due to your event listeners, but without sharing the code for those methods I cannot confirm that issue. The simplest way to fix your double call of the loadPage method would be this:
class A {
constructor() {
this.pageLoadCalled = false;
this.loadPage();
this.events.filter.listen().subscribe((res) => this.loadPage());
this.events.search.listen().subscribe((res) => this.loadPage());
}
loadPage() {
if (this.pageLoadCalled) {
// Exit early (will not call anything below the return)
return;
}
// Mark this method as being called
this.pageLoadCalled = true;
return new Promise((resolve) => {
// do stuff
resolve();
});
}
}
If you want to call loadPage only once, don't execute it when events.filter and events.search trigger:
class A {
constructor() {
// Call pageLoad in the constructor only once
this.loadPage();
// Remove call to pageLoad when events fire.
// this.events.filter.listen().subscribe((res) => this.loadPage());
// this.events.search.listen().subscribe((res) => this.loadPage());
}
}
I solved this using rxjs:
ngOnInit() {
combineLatest(
this.eventsService.subjectSearchDistribution.pipe(
tap((querySearch) => {
this.paginationService.setQuery(querySearch);
this.paginationService.reset();
}),
),
this.eventsService.subjectSortingDistribution.pipe(
tap((sortedList: ListItem[]) => {
this.paginationService.setSortBy(getSortingString(sortedList));
}),
),
this.eventsService.subjectFilterDistribution.pipe(
tap((filterUrl) => {
const page = 1;
this.paginationService.setFilterBy(filterUrl);
this.paginationService.setCurrentPage(page);
this.paginationService.calculateOffsetLimit(page);
}),
),
this.eventsService.subjectFilterDistributionReset.pipe(tap(() => this.paginationService.reset())),
)
.pipe(takeUntil(this._onDestroy))
.subscribe(() => {
this.loadPage();
});
}

Global loaded data in VueJs is occasionally null

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.

Variable is pushed, but it doesn't exist later

I have the following code:
const scenarioList = []
const randomScenario = () => {
return scenarioList[Math.floor(Math.random() * scenarioList.length--)]
}
class Scenario{
setBG(){
//screen.bg = this.bg
//screen.redraw()
}
write(text, buttons, callback){
//$('#gametext > span').html(`<span>${text}</span>`)
//input.setText(buttons)
//input.bindAll(callback)
}
constructor(imgsrc, text, actions, callback){
let img = new Image()
img.src = imgsrc
this.bg = img
this.text = text
this.actions = actions
this.callback = callback
scenarioList.push(this)
console.log(scenarioList)
}
}
I init the class the following (and this is in the global scope)
new Scenario('./bg/1.png', 'You look around and see a huge mountain, what do you do?',[
'Climb It!!',
'Walk around',
'Other Direction',
'Rest',
], [
() => {
alert('a')
},
() => {
alert('a')
},
() => {
alert('a')
},
() => {
alert('a')
},
])
And verify with console.log(scenarioList)
[Scenario]
So its appended, but when I later try to do a console.log() on the same variable it is the following:
[]
Code that causes it:
const startGame = () => {
alert('were here') // this executes at the correct time, but later then variable init.
let scn = randomScenario()
console.log(scenarioList)
scn.write()
scn.setBG()
}
I am not seeing why this would happen, anyone can give me a push in the right direction?
I've found the solution, this code actually removed the element from the array:
const randomScenario = () => {
return scenarioList[Math.floor(Math.random() * scenarioList.length--)]
}
instead I did this:
return scenarioList[Math.floor(Math.random() * scenarioList.length -1)]

react component this.value is null even when it's populated

Here a simplified version of a React component I have:
class Example extends Component {
constructor(props) {
super(props);
this.state = {key : 10 };
this.value = null;
}
componentDidMount() {
this.fetchValueFromServer();
this.fetchSecondValueFromServer();
}
fetchValueFromServer() {
fetch_value_from_server(this.state.key).then( (value) => {
this.value = value;
});
}
fetchSecondValueFromServer() {
is_ready(this.value).then(() => {
console.log("there");
});
}
}
I expect to see the console.log("there") printed but this.value always remains null, even thou is set in the fetchValueFromServer. Why is this?
if you are curious to how is_ready looks it's a simple promise:
function is_ready(variable) {
return new Promise((resolve, reject) => {
let interval = setInterval(() =>
{
if (variable) {
clearInterval(interval);
resolve();
}
}, 100);
});
}
The problem is with the logic of the is_ready function. It looks like you want that function to repeatedly check if that value is there, then resolve when it is. However, because of how closures in JS work, that variable argument will only ever have one value in the context of that function's body, even after this.value changes. Look at this small example:
let secret = 'not found yet'
function checkSecret(secretArg) {
setInterval(() => {
console.log(secretArg)
}, 500)
}
checkSecret(secret)
setTimeout(() => { secret = 'secret found!' }, 1000)
This code will always print 'not found yet', because it's checking the secretArg variable that's been assigned locally, and not the secret variable directly.
Looks like you need to resolve with the variable value within the function is_ready, like so:
resolve(variable);
Then add a param to your console log to determine more, like so:
fetchSecondValueFromServer() {
is_ready(this.value).then((returnValue) => {
console.log("there", returnValue);
});
}
figured it, the value in is_ready is passed by value! Javascript needs to implement & so we can pass crap by ref!

Categories