I would like to make the transition between my pages as seamless as possible. Is there a way for things to happen in this order:
Click on button to change page
Load page to which I'm moving fully (or partially) (no page transition yet)
Do page transition
I'd rather have it this way than click, redirect, and then wait on the page that everything loads.
This loading process would also include calling methods from the new page to do things like make calls to the database etc.
Sounds like a text-book use case for Angular resolvers: You might want to take a look at this.
To summarize the concept: when attempting to navigate to a particular route and there's a resolver configured, everything would be resolved (eg. load some data from backend, prepare it etc) before navigating to the route.
I want to prevent my app from displaying the wrong case of a conditional rendering (before retrieving the data) during the loading phase.
Let me explain, when I'm logged in (the user data is stored via useContext hook) and I refresh my page: automatically the page displays the forms for log in but it disappears a second after that my PWA understands that I'm logged in as it retrieves the user data. How can I prevent that little timing issue ?
Thank you
It should actually be quite easy to keep from rendering it, until you know for sure that it needs to be shown. Something like this:
{this.state.needToShowLogin &&
<LoginForm />
}
In the init part (e.g. class constructor) you start with this value being false. Then change it if & when you decide that it needs to be set to true.
What do I need:
I want to display a loading indicator, when user navigates between pages. I saw an example https://github.com/zeit/next.js/tree/canary/examples/with-loading and it works for me.
In my app I've implemented a similar logic. For an experiment as a loading indicator I just change the color of tag .
try {
if (isLoading) {
document.getElementsByTagName('body')[0].style.backgroundColor = 'red'
console.log('RED')
}
else {
document.getElementsByTagName('body')[0].style.backgroundColor = 'green'
console.log('GREEN')
}
}
catch (err) {
}
And I use events like this:
Router.events.on('routeChangeStart', url => {
setIsLoading(true)
})
Router.events.on('routeChangeComplete', () => setIsLoading(false))
Router.events.on('routeChangeError', () => setIsLoading(false))
What happens:
In a first time, when page is not built yet and not loaded from the server, and user navigates to it, the color is changed and all is fine. But after, when user comes back to the already loaded page, the color of body is not updated.
This code is performed in any case, because I see console.log, but color is not changes.
Interesting thing #1 - if I put 'debugger' before the line of changing the color, then it stops on this line and color updated, even for already loaded pages. As I need.
Interesting thing #2 - If I will use setTimeout for coloring by green, then for already loaded pages, the background will stay green during redirection. After the redirection will be finished, it will became red, and after the timeout it will be again green.
I use:
nextjs 9.1.7
React 16.12.0
Also redux, but I dont think it's important.
It looks like browser does not update DOM while navigation to the already loaded page is performing.
Can anyone give me an advice, what could the reason that for already loaded pages I cannot update DOM when user does navigation?
I found a reason of a problem.
How does it work:
Actually, when page is already rendered and loaded by nextjs, the router renders it immediately after the user navigates on it.
Why the problem did happen:
In my example I had two pages. They contained a lot of data (one of them was especially heavy). After the user navigated to the already loaded page, the browser has started the rendering immediately and it took ~2 seconds. Since the rendering in browser was in progress, it was not able to render the loading indicator. And after the rendering was done, the event "routeChangeComplete" was fired and the loading indicator disappeared immediately after the page was loaded.
What to do:
More correct to refactor the page and make it render faster. Then we don't need loading indicator for the render.
A workaround could be the next - when you want to do a redirect, you need to render the loading indicator first. And only after, start the redirection and therefore a render of the page. The simpliest way, just to test it is use a setTimeout, to delay the redirection.
But I do not recommend this way.
P.S. an example in sandbox worked well because pages there a very lightweight, and long loading was emulated through setTimeout which does not block rendering.
I've found a tool for table management and I love it. The only problem is that it needs initializing as shown below, which means that it only gets called once - when the page's been loaded.
mounted: () => {
$(document).ready(function () {
$("table").DataTable();
}
}
I've put the code in the mounted section and I also tried to use created. For some reason (probably rendering order), I have to keep it in ready method - otherwise it doesn't come up.
This poses two problems for me. Firstly, I'm reusing the same component as a matrix view in multiple components (it's dynamically set up based on the store). Secondly, when I navigate from the page and then go back, it doesn't reinitialize.
How should I make the code inside ready method to run each time the component gets in the view?
I've googled a bit but it's a not so common issue and I'm out of ammo. The best hit I got was the life cycle of the component where I couldn't see anything ground breaking. I also found that the data table instance needs to be destroyed but that only helps if I get to invoke the stuff, which seems not to happen.
I believe you just need to do following:
mounted () {
$("table").DataTable();
}
as $(document).ready detects that the document is ready, but in vue case, mounted is called after the instance has just been mounted where el is replaced by the newly created vm.$el, which should be equivalent of document.ready.
I have also checked in vue 2.x.x that mounted gets called if you navigate from the page and then go back.
If this code is dependent on data being loaded and re-rendering of component, you can use updated instead of mounted which is called after a data change causes the virtual DOM to be re-rendered and patched.
updated () {
$("table").DataTable();
}
I have a mobile single-page web application that is built using jquery-mobile (jqm) and knockout. The application itself has multiple pages but they are all contained within a single HTML document.
Problem: after changing my "create view model for page" from sync to async behavior, I have the problem that jquery-mobile fires its events before the data is ready.
Background: up until recently I had been working with sample data, basically a huge JSON blob, and everything worked smoothly. With the new async composition of view models from various sources, data is not ready immediately and my "buildViewModel" method takes a continuation callback instead of just synchronously returning data.
I'm subscribing to the pagebeforecreate and pagebeforechange events, and fire off the code to populate the viewmodel here. The problem is that after returning from the event handler, jqm triggers the remaining chain of events before the data is available. This causes a page transition to an unprepared page, which is undesirable.
I have tried to call event.preventDefault in all of the before-events and manually calling $.mobile.changePage once the page is ready to be a) enhanced and b) the page transition to occur, but without any luck.
I've scanned the jquery-mobile source, but couldn't spot anything that looked like it would allow me to delay the pagebeforeshow event, which is essentially what I need in order to be able to render the page properly.
How can I ensure that 1) data is available and 2) knockout has been applied to perform initial DOM manipulations, before jquery-mobile attempts to enhance the page and before it executes the in-transition to the page?
I also considered using synchronous ajax to fetch resources, but this will (I think) not work for resources loaded from the device (using PhoneGap/Cordova), and has other negative consequences that I'd like to avoid.
FWIW, I'd like to avoid having to manually handle all navigation events by wiring up click-handlers everywhere, but I'm open to all solutions if need be.
Apologies if this is a duplicate; I've searched and read a ton of questions, but not found an answer or question that was quite the same. It just sounds incredible that I would be the first to hit this problem, as I imagine it is a common scenario..
Update: clarified problem scenario description.
I had this exact same problem.
The only solution I've been able to come up with is to write a custom transition handler that defers starting the transition until the Ajax request completes.
Here's a fiddle showing the technique. The fiddle doesn't use Knockout, but does show how to defer the transition.
Basically, since $.ajax() returns a promise, I can pipe that into the promise returned by the default transition handler and return it from my new handler.
In my pagebeforeshow handler, I attach the Ajax promise to the page so that the transition handler has access to it. Not sure if this is the best way, but I liked it better than using a global variable.
The only thing I didn't like about this is that it delays the start of the transition until the Ajax response arrives so it could feel like the page has "hung" to the user making them click again. Manually showing the loading message makes it feel a bit more responsive.
Hope this helps and please let me know if you find a better solution!
Delaying the transition to a new page until its content is ready is a very common issue when facing dynamic content in jQuery Mobile. The most convenient ways to address this are:
Instead of classic href type navigation, base the links on "click" actions that will first retrieve the content, build a new page in the DOM, and then initiate a transition to this new page through $.mobile.changePage. The advantage of this approach is that it is easy to put in place, the disadvantage is that you do not navigate with classic href links
Bind the pagebeforechange event at the document level to detect if upon navigation the target page is one of your page that should contain dynamic content. In such a case, you can prevent default navigation from happening, take your time to generate the page, and transition upon success. This is described in the JQM docs on dynamically injected content. The advantage is that you can still rely on standard href links navigation, but it requires a bit more code and design upstream to properly detect and act upon navigation to the pages.
$(document).on( "pagebeforechange", function( e, data ) {
if ( typeof data.toPage === "string" ) {
if ( data.toPage === "myDynamicPageName" ) {
e.preventDefault(); //used to stop transition to the page (for now)
/*
Here you can make your ajax call
In you callback, once you have generated the page you can call
$.mobile.changePage
(you can pass the Div of the new page instead of its name as
the changepage parameter to avoid interrupting again the page change)
*/
}
}
});
Set your link to call a "load" function instead of doing a page transition. In your load function, display the "loading message" and make the JSON call. Finally, in the JSON callback function, change page to page2
The load function:
function loadPage2() {
/* show wait page */
$.mobile.loading( 'show', {
text: 'Loading massively huge dataset',
textVisible: true
});
/* perform JSON call then call callback */
}
Callback function
function callback() {
$.mobile.changePage("#page2");
}
Here is a working JSFiddle: http://jsfiddle.net/8w7PM/
Note that if you don't want users to be able to update input fields in Page 1 while waiting, introduce a "wait page" between page 1 and page 2, with the init of "wait page" doing the same as "loadPage2".
I think you have to fire again for all widget which you want to bind the data from response to
For example, you will have to invoke trigger with create or refrestevent for the element
$("#element").trigger('create');
JQuery Mobile will bind all default events to the element as it is
--- EDIT ---
I just created a sample code, I think it's same your issue, please try the link http://jsfiddle.net/ndkhoiits/BneqW/embedded/result/
Before rending the data, we have to invoke to service to get them for displaying, that why all events binded by jqm will be removed then.
I have a workaround for this, don't make jqm fire anything on the element, we'll trigger it after all data is binded by knockoutjs
Let try the fixed version
http://jsfiddle.net/ndkhoiits/c5a2b/embedded/result/
This is the code http://jsfiddle.net/ndkhoiits/c5a2b/
I have a small jQuery Mobile / KnockoutJS application and have struggled with the very same issue. My app contains about 5 pages. All are contained in a single physical HTML document with the standard <div data-role="page"> markup separating individual pages.
I finally went with click based navigation and fire $.mobile.changePage() as the result of $.ajax success.
One of the downsides to this technique is that you will lose your button highlighting when relying on onclick vs href attributes. See my related post: href vs scripted page transitions and button highlighting
I later chose to supply both and rely on the href to perform the navigation while using onclick to invoke my JavaScript logic to load ViewModels etc. The only place that I have found this to be an issue is when there is possible validation required on the source page. If it fails, the transition has already started and the UI then flashes back to the source page. Ugly but this only happens in limited instance within my app.
I don't think any of this is specific to Knockout. My exact solution may present issues for you in that your navigation is likely to complete before your model is fully loaded but if you rely on $.mobile.changePage(), it should all work and hide your page until after it is loaded. The transitions should work fine.
<a href="#MyNewPage" data-bind="click:LoadNewPage" data-role="button">
Load Page
</a>
$.ajax({
url: url,
cache: false,
dataType: "json",
data: requestData,
type: "POST",
async: true,
timeout: 10000,
success: function (data, textStatus, jqXHR) {
// use either href or changePage but not both
$.mobile.changePage("#NewPage");
},
error: function (jqXHR, textStatus, errorThrown) {
alert("AJAX Error. Status: " + textStatus);
// jqXHR.status
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
}
});
You should place the code for the page transition in a success function on the AJAX call.
$.ajax({
url:"request-url",
data: data,
type: "POST",
success: function(response){
// Add Transition Code Here
}
});