Losing data on a browser refresh in Vue.js application - javascript

Background
In a Vue.js application I am calling Getter VueX function in the mount life cycle method. This works great and retrieves all my customer data when the page loads.
The problem I seem to be facing is when I refresh the web page the mount method does not fire and the data is all removed from state which I have no access to till I navigate away from the page and then come back. At the point I return the mount function fires and I have the customer data back again.
Example
mounted() {
this.getCustomers();
},
async getSelected() {
console.log("Customer ", this.customer.email);
this.currentCustomer = this.customer;
this.updateCustomerData.clientID = this.currentCustomer.client_id;
this.updateCustomerData.email = this.currentCustomer.email;
this.updateCustomerData.password = this.currentCustomer.password;
this.customer = this.customer.email;
await this.RECEIVE_CLIENT_NOTES(this.currentCustomer.client_id);
},
That function above calls a VueX Getter to retrieve data that is used inside of a Material Auto Complete Search component. It fires off when I navigate to the page but does not fire at all when I am on the page and refresh. The refresh clears the state and leaves me without data on page reload.
Question
How should I handle page refreshes in order to maintain my data or recall the Getter from VueX to repopulate my data?

Related

Delay in loading the response when I am switching between tabs present in the header of vue component

I have vue component in which I have multiple options(tabs) like "All, Submitted, Rejected etc" on my header. According to the functionality when I click on any of the options, the data for them loads from the api's. I have defined the all the api's on the same component for all the options.
Now when I switch between these options the api with large data takes time to load which is affecting the content of that particular option.
switch (arg) {
case this.statusVal[0]:
this.activate(arg);
this
.$router
.push({
name: "sales-approver-dashboard",
params: {
dropType: this.headerDropdownClaim,
approverClaimType: this.statusVal[0]
}
});
this.fetchData()
this.claimTableData.claimStatus = "";
break;
case this.statusVal[1]:
this.activate(arg);
this
.$router
.push({
name: "sales-approver-dashboard",
params: {
dropType: this.headerDropdownClaim,
approverClaimType: this.statusVal[1]
}
});
this.fetchData()
this.claimTableData.claimStatus = this.statusVal[1];
break;
the fetchData() functions calls the post request which has the response containing the data of each options. So when I quickly move between these options, the response with large data is taking more time to load while I am already in the different tab having less data whose response is already loaded but it is showing the data of last loaded response(as it contains the large amount of data)
Edited question
I am opening the dashboard having different tabs/options to switch between.
On first load api with data is calling having all the data.
I am calling the fetchData function which is basically displaying the data through post request and taking the response only which is required on that page based on the pages/tabs.
I am switching between the tabs through routing of vue js as above code (case1, case2) and each tab is again calling that fetchData function which shows the data based on that tab.
So when I routes between tabs, suppose I have large response for first tab and very less for the tab on which I have moved on. So what is happening in that case, that previous page fetchData function is still in execution but I have routed to next page which has less response let's say only one data. Because of that it loads quickly but the previous function is still in execution and loads after the this one.
Because of that the data of 2nd tabs loads first and I am able to see that data on screen but as soon as the first function is executed that data is now displayed on the screen which is wrong.
So is there any solution like we can stop the execution of that previous function as soon as route to next page.

how to pass data consistently from page to page in Vue Js?

Currently I want to pass data from edit page to add page. So i pass the query using {path: '/test/admin/clinicvisit/add', query:{id:this.$route.params.id}}. I was able to pass the data to add page using the query however sometimes the data may not present when it refreshes a few times. Is there any possible way to make the data consistent stay in the add page ?
add.vue
async testRoute(){
let visitId = this.$route.query.id
if (visitId){
let clinicVisit = await this.api.medical.viewClinicVisit(visitId)
this.inputs = await this.api.medical.optionsClinicVisit()
this.$set(this.inputs.staff, "item_text", "username")
this.$set(this.inputs.staff, "item_value", "id")
this.$set(this.inputs.staff, "items", await this.api.profile.listStaff({}))
if(clinicVisit.staff){
this.$set(this.inputs.staff, "value", clinicVisit.staff)
this.$set(this.inputs.staff, "tmp_value", clinicVisit.staff_detail.name)
}
mounted()
{
this.testRoute()
}
This can be done in multiple ways.
Using a global store, You can use a library like Vuex to share the state between the components.
Using the Local Storage, if you want to preserve the data and keep saved after hard refreshing the page.
Using Session Storage, if you want to preserve the data and keep saved during the user session, but whenever the user close the browser tab it will be gone.
When you observe that the data is not present after a few refreshes, does it dissapear from the URL in your browser, or does it just not load?
If you want the data to stay more consistently, consider using localStorage
localStorage.setItem('item_text', 'username') //Save variable in browser data
let item_text = window.localStorage.getItem('item_text') //Get variable from browser data
EDIT:
If the URL is still present in the browser window, that sounds like a weird loading bug, where your code runs before the route is parsed by Vue.
You can try using a watcher instead of the "mounted" function:
watch: {
$route: {
immediate: true,
handler() {
this.testRoute()
}
}
}
I solved this error by setting a timeout function in my edit.vue.
handleCreate(event){
event.preventDefault();
this.$router.push({path: '/medical/admin/clinicvisit/add', query:{id:this.$route.params.id}},2000)
// now 'this' is referencing the Vue object and not the 'setTimeout' scope
this.loadClinicVisitData = true;
setTimeout(() => this.loadClinicVisitData = false,1000)
}

Angular: data passed from another component becomes undefined on the page reload

In my angular app, I need a component to pass data to another component which do not have parent child relationship.I have an Orders table in one component with each row representing an order. When user clicks on any specific row, I need navigation to OrderDetails component& pass the order object representing the clicked row along with it
validation.component.html
<tr *ngFor="let order of allOrders" (click)="onNavToOrderDetails(order)">
<td>{{order.id}}</td>
</tr>
validation.component.ts
onNavToOrderDetails(order) {
this.router.navigate(['orderdetails'], { state: {data: order} });
}
orderdetails.component.ts
order;
ngOnInit(): void {
this.order=history.state.data;
console.log(this.order);
}
orderdetails.component.html
<p>{{order.id}}</p>
orderdetails.component.html displays order id when navigated from validation.component.html but refreshing the orderdetails page cause order id to disappear. I understand on the page refresh history.state.data becomes undefined but how to get around this issue? Since the app is a SPA, storing the data from the validationcomponent to a service and using that service in the orderdetailscomponent won't work either.
Page refresh means reloading the entire angular app ,and order object stored in the serivce by the validation componentwill also disappear. How to solve this issue? I want previously stored data in a serivce to stay unaffected and display it again on page reload?
There are 3 ways to handle it:
Use sessionStorage (don't go for localStorage) , but then make sure to maintain sessionStorage data as per the scenarios
ngOnInit(): void {
if(history.state.data){
this.order=history.state.data;
sessionStorage.setItem('order_page_info', JSON.stringyfy(this.order));
}else{
this.order = JSON.parse(sessionStorage.getItem('order_page_info'))
}
}
Use Cache (not recommended)
Rather than passing entire data, pass the id as router data and make server call to fetch details for the id. This would maintain id in url and so you can fetch details on refresh by calling the server
try putting ngOnChanges
ngOnChanges detects changes from other component specially from api call of services
ngOnChanges(){
this.order=history.state.data
}

Send Info after browserHistory.goBack

I'm building an App with reactjs and in some point I have a SearchForm, then I click on one of the items and in that view I have a back button.
What I want is to populate the search form with the previous data. I already achieved it with localStorage from javascript. And saving the state on componentWillUnmount, the problem is this data is always loaded even if I don't arrive from the go back.
Is there a way to add a kind of state to the goBack to tell it?
So, the best way here is to not use localStorage, and instead use history state.
When the user updates the form, you can do this (optionally debounce it for better performance):
history.replaceState(this.props.location.pathname, {
formData: JSON.stringify(formData),
});
Then when the component loads, you can access that state like this:
const {location} = this.props;
const routeState = location.state && location.state.formData;
if (routeState) {
this.setState({
data: JSON.parse(routeState),
});
}
If they refresh the page, or go to another page and go back, or go back and then go forward, they'll have that state. If they open it in a new tab, they won't have the state. This is usually the flow you want.

History.js getState() at pageload

I'm a little confused about how History.js works at page-load. I've done a few experiments but the results seem indeterministic.
My website is a search engine and the query is stored in the URL parameters: ?Query=cats. The site is written purely in javascript. History.js works great when I do a new search, the new query is updated, and the state is pushed.
My problem is how to create an initial state if the user manually enters in a URL including a Query parameter. Every way I try to do this ends up resulting in running the search query twice in some case. The two use-cases that seem to conflict are:
User manually enters URL (mydomain.com?Query=cats) into address bar and hits enter.
User navigates to an external page, and then clicks the back button
In both cases, the javascript loads, and therefore looks to the URL parameters to generate an initial state.
However, in the second case, History.js will trigger the statechange event as well.
Necessary code:
History.Adapter.bind(window,'statechange',function() { // Note: We are using statechange instead of popstate
var s = History.getState();
if(s.data["Query"]){
executeQuery(s.data);
}
});
and in $(document).ready I have
// Get history from URL
s = getQueryObjectFromUrl(location.href);
if(s["Query"]){
History.pushState(s,'',$.param(s))
}
Is there a better way to handle creating an initial state from URL parameters?
As I had a similar problem to to yours, what i did was to define the function bound to a statechange as a named function, and then all I had it running when the page load as well.
It worked better than trying to parse the URI or anything else, hope it helps.
This is the way I chose to do it (based on Fabiano's response) to store the initial state parameters
var renderHistory = function () {
var State = History.getState(), data = State.data;
if (data.rendered) {
//Your render page methods using data.renderData
} else {
History.replaceState({ rendered: true, renderData: yourInitData}, "Title You Want", null);
}
};
History.Adapter.bind(window, 'statechange', renderHistory);
History.Adapter.onDomLoad(renderHistory);
Of course if you are using a different on DOM load like jquery's you can just place renderHistory(); inside of it, but this way doesn't require any additional libraries. It causes a state change only once and it replaces the empty initial state with one containing data. In this way if you use ajax to get the initData inside the else, and it will not need to get it the next time the person returns to the page, and you can always set rendered to false to go back to initial page state / refresh content.

Categories

Resources