Skip to content
This repository

No longer able to remove / expire pages reliably #2520

Closed
dgeb opened this Issue · 29 comments

8 participants

Dan Gebhardt Kin Blas John Bender Todd Parker Scott Jehl Robin Andersson ahutch Zero3
Dan Gebhardt

It no longer seems possible to invalidate content reliably. If a user loads /page1 and then navigates to /page2 and performs an action that should change the content on /page1, navigating back to /page1 will show the originally loaded page.

In Alpha4, I could remove pages from the DOM when they were hidden, but this approach now screws up the history and back / forward navigation.

I've tested this with Beta3 and the latest. It seems like a major issue for dynamic apps.

Todd Parker

Seems like our Dom cleanup is causing you issues. Are you enabling Dom caching in the global options to tell the framework to not delete pages as they are hidden? If so, please post a jsbin or jsfiddle and we'll take a look.

Scott Jehl
Dan Gebhardt

Hi Scott and Todd,

Thanks for your responsiveness.

If I set data-dom-cache="true" on page elements and then remove pages myself in pagehide events, then any back navigation leads to a blank page (i.e. the page is not reloaded). I've also tried to manipulate $.mobile.urlHistory.stack with no success.

If I set data-dom-cache="false" (the default) on page elements, then there doesn't appear to be any way to invalidate the content on the initially loaded page. It always seems to be loaded from cache when navigating back to it.

Do you need any clarification or have any suggestions? Thanks in advance.

Scott Jehl
Dan Gebhardt

I'm testing in Safari 5.1 (6534.50) in OSX using the iOS 4.3.3 user agent. I've also tested in Safari in iOS 4.3.3 directly, and the only difference seems to be pushState support.

I'm running this on a development server with no caching headers set.

I think that the most interesting detail is that the initial page is never cleared from the DOM. It remains loaded, with its full content, as follows:

<div data-role="page" data-theme="b" data-dom-cache="false" data-url="/page1" tabindex="0" class="ui-page ui-body-b" style="min-height: 747px; ">
  ...
</div>

This initial page is never cleared from the DOM, regardless of how many pages I visit. However, other pages are cleared from the DOM as expected. Only the initial page and the current page ever seem to be present, so data-dom-cache="false" is working to some extent.

Dan Gebhardt

I realize that you're on a tight schedule to try to get RC1 out. If you provide some guidance on the components involved in this issue, I can look into it. Just let me know...

John Bender

@dgeb

I'm curious why when you disable the dom cache removal you're having navigation issues. Can you post an example with it disabled like so?

$( document ).bind( 'mobileinit', function() {
  $.mobile.page.prototype.options.domCache = true;
});
Scott Jehl

Hey dgeb,
I guess page removal does appear to be working as described, as it's only meant to be enabled on pages that were loaded via ajax. Should we change this issue to a feature request for removing the initial page?

Dan Gebhardt

@johnbender

Yes, setting domCache = true globally works as advertised: pages remain in cache. However, since my apps have dynamic content on every page, I need a method to invalidate that content so that it will be reloaded whenever the page is viewed. If I remove pages from the cache myself, back / forward navigation can lead to blank pages.

@scottjehl

Thanks for confirming my findings. I would still consider it more of an issue than a feature request because it is not how I would expect the domCache option to work. I understand that much of the reasoning behind introducing this option is to keep memory usage down. However, another reason to use this option is to control the caching of pages, which is vital to any app with dynamic content. Even if you'd like to keep domCache working as is, I strongly feel that there should be some way to invalidate pages to force content to be reloaded.

Thanks for hearing me out! I'm certainly willing to pitch in to help once a consensus emerges on the proper approach.

Robin Andersson

@dgeb

I can also confirm that the initial page will stick in the DOM even if it have the data-dom-cache attribute set to false.

Todd Parker

We'll discuss this a bit more internally to decide whether expiring the page is worth a re-look.

John Bender

@dgeb

In Alpha4, I could remove pages from the DOM when they were hidden, but this approach now screws up the history and back / forward navigation.

When we disable domCache globally it should behave in the same fashion it did prior to its inclusion in the library, which means that's a bug. Also, if we can get that working you'll at least have a workaround.

[edit] clarification

Dan Gebhardt

@johnbender

Thanks for the clarification. I agree that the inability to cleanly remove cached pages is a separate issue from the "sticky" initial page when caching is disabled. Maybe they should be separated in Github. A fix to either issue would be most appreciated and allow me to upgrade my apps.

Although I said that the removal of cached pages on pagehide hasn't worked since Alpha4, I verified that it also works in Beta1 (but hasn't worked since then). I've tried simply removing pages from the DOM and also manipulating the $.mobile.urlHistory.stack without success.

If it would be useful, I could cook up a demo of the problem(s).

John Bender

@dgeb

It could be from any other host of changes we made to nav in the meantime including how we reference the pages in the history (data attr selector). The team will have to chat.

John Bender

@dgeb

After talking with the team it would be really great if we could have an example where you've got domCache=true and you're trying to remove the page yourself. The simpler the better. Keep in mind we can't reproduce embedded pages if you're removing them.

Dan Gebhardt

I've created a demo project that shows all the behavior discussed in this thread:
https://github.com/dgeb/jquery-mobile-test

There are three different branches. Each explains what's going on in the README:
https://github.com/dgeb/jquery-mobile-test/tree/jqm1.0b1
https://github.com/dgeb/jquery-mobile-test/tree/jqm1.0rc1_with_domcache
https://github.com/dgeb/jquery-mobile-test/tree/jqm1.0rc1_without_domcache

@johnbender - the second branch is the one you requested.

FWIW, I tested in Safari.

ahutch

I too have been having issues with the domCache=true and domCache=false using the latest and agree with dgeb.

I wanted to change the caching of a page in pagebeforehide. The reason being that sometimes I want to be able to return to a page without the content reloading but most of the time I want the page refreshed. Take for example an info, confirmation or dialog page. When I open the associated page I want to be able to return to the exact prior page in the state that the user left it. Otherwise it should reload. This problem becomes much worse on a phone in which multiple pages need to be linked and need to be cached until the user returns to the root.

Also if the first page loaded is not the root page then I expect to be able to remove it when the root page is loaded.

I see in JQM that the callback to remove a page ($.mobile._bindPageRemove) is only attached in the pageLoad function. The attaching of the callback depends on the initial state of domCache and changing it later has no effect. Also I cannot find any code that unbinds the page removal.

Why would you not always bind the page removal callback and check the domCache value when it is needed?

Zero3

I can reproduce the blank page problem too. It's a dealbreaker :/.

Has anyone found a workaround? I've tried messing around with the history stack too, but, alas, without luck.

Zero3

Using dgeb's example, I've bisected the blank page issue for the main page. Maybe it can help you guys:

78041bc is the first bad commit
commit 78041bc
Author: Kin Blas jblas@adobe.com
Date: Thu Sep 8 09:21:31 2011 -0700

Added path.isFirstPageUrl() which is now called from loadPage() when trying to determine if the URL being loaded refers to a page that is already in the DOM. This will prevent us from duplicating the first-page in the main application document.

Also checking in the first example of how to use the pagebeforechange notification to allow for dynamically updating and re-using a page that is already in the DOM.

:040000 040000 53a9ebc2e3b561d0969dc5ecb48f54f6fbf2f6f7 0d3b865d86a7c0f501b4eeb3beb15fc2eef68360 M docs
:040000 040000 d758ffc4192e5968807525e0f988f12d5860b08b 74eb49f92dcf15b49ed45d7d2c0c2a434a80b90d M js

Kin Blas

@Zero3

Are you reproducing this "blank" problem in your own app? If so, can you post an example so we can see exactly what you are doing?

Zero3
Dan Gebhardt

The blank page problem results from removing pages from the cache as soon as another one is shown. It is illustrated in this branch of my test:

https://github.com/dgeb/jquery-mobile-test/tree/jqm1.0rc1_with_domcache

Kin Blas

@dgeb

I see why it's happening. You are removing the first-page of the application document, which the framework always assumes will be available. In fact it tracks it because of special path circumstances, and this specific check was made to prevent duplication of the first-page by accident. I suppose that I can check to see if $.mobile.firstPage has a parentNode before resetting the page being loaded.

Kin Blas

I have a fix for this, I'm just writing up the unit test for it. I'll land it shortly.

Dan Gebhardt

@jblas

That's great news - thanks very much!

Does your fix also remove the first page when data-dom-cache="false"? The fact that this doesn't happen is surprising to many developers (as illustrated by the length of this thread). This scenario is covered in this branch of my test:

https://github.com/dgeb/jquery-mobile-test/tree/jqm1.0rc1_without_domcache

Thanks again!

Kin Blas

@dgeb

No, it does not include pruning embedded pages. The main reason we cannot do this is because we don't have the ability to load random pages from external documents. We only load the first page of external documents. This is fine for your case, because your document only contains one page, but there are lots of folks using app documents that have more than one embedded page (for the commonly used pages) and pull in external pages that need to be more dynamic or are less-used.

@ahutch

Regarding your issue of wanting to conditionally prune, the framework fires off a 'pageremove' event just before it attempts to remove the page from the DOM. If you call preventDefault() on that event, the page will be left in the DOM. This allows you to control whether a page gets pruned whenever it gets hidden.

ahutch

@jbas

So you are recommending that allow the default behavior of data-dom-cache="false" and when the app needs to keep a page, in order not to reload it when the back button is pressed, prevent the 'pageremove'? Does the pageremove event have access to the same information as the page events (ui.nextPage)? I have only one page that is dynamically cached, it is cached unless you return to the root.

Also I am not clear on how I can prevent caching of the first page loaded. By default it is cached. I have tried data-dom-cache="false" on the page before it is loaded but it did not work. If this is supposed to work then I will try it again. However this would mean I have to add data-dom-cache="false" to every single one of my pages just in case it is the first one loaded. I have only one page I want cached permanently which is the root page.

In the way the cacheing has evolved it would seem to me that you should not cache any page unless specifically requested (data-dom-cache="false"). Even embedded pages.

Kin Blas jblas referenced this issue from a commit
Kin Blas Fix for issue #2520 - No longer able to remove / expire pages reliably
- Modified loadPage() so that if we are attempting to load the first page of the application document, that we first check to make sure it is in the DOM before returning our cached copy. If it is not in the DOM, we let it fall through to the ajax loading code so that it gets recreated. This is necessary since some developers are agressively pruning pages, including embedded ones, for various reasons.
97e3f8a
Kin Blas

Fix landed on the HEAD. Should appear in 1.0 final as well as /latest/.

97e3f8a

Kin Blas jblas closed this
Dan Gebhardt

Thanks very much for the fix @jblas. I've confirmed that selective caching of pages is now possible, regardless of whether pages have been embedded. I created a new branch to my test project to illustrate how selective caching can be done:

https://github.com/dgeb/jquery-mobile-test/tree/jqm1.0_latest_with_selective_caching

In this sample, you can set data-dom-cache="true" on individual pages to force them to be cached. All others will be removed by a pageshow event handler like this:

$(document).bind("pageshow", function(event, ui) {
  var prevPage = ui.prevPage;
  if (prevPage && prevPage.attr("data-dom-cache") != "true")
    prevPage.remove();
});

For the record, I still don't understand the special status being given to embedded pages. Even if multiple pages are embedded in the initially loaded page, they could be subject to the same rules of dom caching as external pages if marked with data-dom-cache="true". This would negate the need for custom code (like my example) to override the default (and IMO unexpected) caching behavior.

Timmy Willison timmywil referenced this issue from a commit in timmywil/jquery-mobile
Kin Blas Fix for issue #2520 - No longer able to remove / expire pages reliably
- Modified loadPage() so that if we are attempting to load the first page of the application document, that we first check to make sure it is in the DOM before returning our cached copy. If it is not in the DOM, we let it fall through to the ajax loading code so that it gets recreated. This is necessary since some developers are agressively pruning pages, including embedded ones, for various reasons.
615647d
Timmy Willison timmywil referenced this issue from a commit in timmywil/jquery-mobile
Kin Blas Added unit test case for issue #2520 (No longer able to remove / expi…
…re pages reliably).
95e7dd1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.