Page life cycle with pagecontainer: Reasons to keep 'pageshow' event #7283
Comments
I have made this post explaining page cycle of a page in jQM 1.4. Unfortunately, between all events, only two events can be attached/delegated to page div Initializing plugins such as Google Maps won't function as they should because page div is still hidden and dimensions are unknown. They should be initialized on Using I second @wauwau0977 on this issue. Please, we want the old events back. Thanks! |
I support @wauwau0977 and @Palestinian on this, the new 'pagecontainershow' does not really encapsulate one of the elements of jQM that I have always seen to be a core feature, namely to handle page cycle events with relative ease and clarity. The current solution would make me rather use another framework for more complex scenarios, since it architecturally inhibits a more modular approach. |
I agree as well, I feel as if jQM 1.4 took a step backwards in this area, requiring much more code and adding much more confusion to things that should be fairly "simple" |
You can do this yourself, but why should you have to write a work-around for something so fundamental and useful? It is useful to fire events on the objects that have the greatest need to know about them. Most of these events concern (primarily) the page that is involved. It is almost always page-related code that is interested in An "if" statement in a document-level callback is not a good alternative. It means that code that applies to a specific page (or class of pages) has to be dealt-with at the document level. It makes it difficult to write modular code. Given the level of sophistication of the average jQuery Mobile developer (low - not meant to insult anybody, just an observation...) this is going to create tons of awful spaghetti-code. This seems an issue of purity of concept winning over ease of use. The end effect is it appears the developers want to make it difficult to use. Makes no sense. Work-around is to catch these events on So, now everybody is going to be writing their own code (with their own bugs) and inventing their own names for these events. Why not do this in a standardized way and make it an option? This is somewhat less efficient than the old way, because now the document will get an event, and then the user's own code will reflect it down to the page, from which it will then (potentially) bubble back up to the document. (Which is another reason why the reflected events have to have a different name!) |
Hi just want every one to know we are listening to you and reading these comments. I am currently working on a solution i hope will please everyone. I will post more details shortly once a few things are finished up and the changes will be coming in 1.4.3 Thank you for your patience on this. |
To clarify, I'm going to post one of our typical .js files (a short one). I believe that this is typical of the type of code that wawau0977 is talking about when he speaks of "modules". I suspect this is a pretty common design pattern for jQuery Mobile JS code. Of note is the caching of various in-page selectors on Edit: OK this isn't really a great example. If we want, say, to do something on /*jslint browser: true, devel: true, vars: true, unparam: true, white: true, indent: 2 */
/*global jQuery */
(function photoEditListSelfEx($, window, document, undefined) { // Ignore JSLint error on undefined
'use strict';
// Note that edit_list.js now handles most of photo_edit's JS needs.
// Only need new Photo and new Drawing code
$(document).on('pageinit', '.page_edit_photo_list', function() {
var $page = $(this);
var auditID = $page.data('audit-id').toString();
var $list = $page.find('.one_to_many_item_list');
var $newPhotoBtn = $list.find('.nav_to_new_photo');
var $newDrawingBtn = $list.find('.nav_to_new_drawing');
$page.on('pagebeforeshow', function() {
// Do somewhere here before the page is shown. Typically, populate something,
// hide/unhide something, clear "active" classes, etc. etc.
});
$newPhotoBtn.on('vclick click', function(event) {
event.stopPropagation();
event.preventDefault();
if (event.type === 'click') { return; }
var $a = $(this);
var $btn = $a.closest('.ui-btn');
$btn.addClass('ui-btn-active');
$.post( '/app/Photo/new_photo', {id: auditID} );
});
$newDrawingBtn.on('vclick click', function(event) {
event.stopPropagation();
event.preventDefault();
if (event.type === 'click') { return; }
var $a = $(this);
var $btn = $a.closest('.ui-btn');
$btn.addClass('ui-btn-active');
$.post( '/app/Photo/new_drawing', {id: auditID} );
});
});
}(window.jQuery, window, document)); |
@jtara thank you for your example however pageinit is an event issued by the page widget it is only being deprecated because it is no longer needed. It's original purpose was it provided a particular timing needed for some widget auto enhance code. However this was due to our old event based autoinit which we have since replaced with a non event based solution which allows for better timing so no the page widgets built in create event can be used and init will be removed. If you have a use case where pagecreate does not properly replace pageinit please open a separate issue for this. However this issue is about page events vs pagecontainer events which is a very different issue. Note: looking briefly at your code the only thing you need to do is change pageinit to pagecreate in your first binding. |
^ Yes, I understand
But what about OK, I guess I can listen at the document level within my module, and test with an This means if you have a bunch of modules, you will have a bunch of document-level callbacks needlessly listening to stuff they don't need to listen to, testing with an Is this inefficient? Probably not very. Should be roughly the same as what is already going on when you delegate to document. But you'll note that my code does't delegate to document. It binds to page (for Can we please have something in the documentation similar to this for 1.4?: http://bradbroulik.blogspot.com/2011/12/jquery-mobile-events-diagram.html |
@arschmitz thank you, we look forward to seeing page events revived. |
@arschmitz, @jtara, @Palestinian, @simsam7, @livewire1407: These are great news. What a great promise and what a quick reaction time... Big thank you :-) |
@wauwau0977 Yup, great news from a great team. |
Thanks @arschmitz and the jQM team for responding to feedback like this & also thanks to @Palestinian and @wauwau0977 for pushing for it in the way that you have! :-) |
Ok sorry to keep every one waiting but wanted to make sure a few things were ironed out before saying anything. First i would like to say thank you for all the feedback we do take this and the use cases you present seriously. We however will not be keeping the old page events these were fundamentally flawed because page events should be issued by the page widget but most of these events the page widget is oblivious of. Previously these events were emitted from our navigation system so they had no real paradigm to follow. However in 1.4 we created a page container widget which now handles all the navigation. The pagecontainer widget is now the home of these events and widget have very specific rules which they follow for emitted events they are always emitted on the actual element the widget is initialized on, they always use the name of the widget as a prefix. The page container widget is the logic place of these events because it is where the pages are controlled and it is what is performing all of the actions in the described by the events. However the pagecontainer events were not implemented very well and this needs to be fixed. The first this we are going to do to fix this situation is all pagecontainer events will now contain a toPage and prevPage property on the ui object passed to the event handler so it will always be possible to know what two page you are dealing with prevPage will always be a jQuery object containing the current page ( except on initial page load where it will be undefined ) toPage will initially be a string containing either the string passed to the change method or the href on the link clicked and will switch to a jQuery object once the page is loaded ( except when it is the initial page load or when a jQuery object or DOM node is passed to change in which it will contain those ) The next problem we will fix is that only some of the page events had a corresponding pagecontainer replacement which we feel is inconsistent and confusing so now all page events ( except those actually issued by the page widget ex: pagecreate, pagebeforecreate, pageinit ) will now have a corresponding pagecontianer replacement. you can see a table of our plans here https://docs.google.com/spreadsheets/d/10FBrCSUFCmLIbJlODJCXvLNmKSUqQesWIX41H26YWsc/edit?usp=drive_web With these all you will need to attach your events just as before you will just need either an if or a switch or similar to check if the event is for one of the pages your looking for. Additionally i have created 2 tools to to help with using the new events. First is a pair of jQuery plugins called onPage these allow you to attach events the same way you did in 1.3 with one minor change instead of doing something like The second tool is a plugin to help in debugging events you can enable it for groups of events and it will log or alert all of those events along with their target and their ui object and the description of the event from the api docs. This tool is tied directly to the api docs and will always stay up to date and has an option to turn on or off deprecated events. you can see this tool here https://github.com/arschmitz/jquery-mobile-event-debugger. in addition we are working on demos showing all of these new events their usage as well as demos for the plugins to help with converting. Finally page events will remain for 1.5 to give additional time to switch but all updates I mention here will be in 1.4.3 I know this is was long but i wanted to fully explain the changes we are planning so we could get everyones opinion. |
@arschmitz Thank you for sharing those handy plugins. Could you please tell us why jQM team has decided to deprecate "Page Events" and replace them with "Page Container"? Is it performance issue? I assume that using |
The event debugger is nice. It's nice some effort is being put into cleaning-up the documentation. That said, this is not what I was hoping for. "With these all you will need to attach your events just as before you will just need either an if or a switch or similar to check if the event is for one of the pages your looking for." That's what I'm trying to avoid. OK, next?
I don't find that particularly useful, either. It's equally inconvenient as the first solution. The sensible thing here is to have events fired on the page, not it's container. The new way is clean and pure, to be sure. The old way was better for programmers. Silly me, I like programming stuff to be better for programmers... A plugin to bring back the old 1.3 events would be fairly trivial. Just catch these events on the page container and reflect them to the page. Unfortunately, this means a name change for all of the events to maintain compatibility until the old events are finally removed. Actually, it would be better to just rely on the existing support for the old events until they are removed. The plugin should backfill the new events that have been added in 1.4. Test for existence of the old events, and if not present (1.5 or whenever...) then also reflect the corresponding page container events to the old event names (on the page object). And that's my plan. This "solution" is not useful to me. A plugin providing the old events (as well as new ones fired on page) allows me to rescue existing code, and, as well, continue to work with page-level events (Imagine that! Events that concern pages fired on pages! What will they think of next? Donuts with holes?), which are much more convenient to work with. |
+1 for the above post. At this point, I just wish the pagecontainer events were delegate-able. If I could do $(document).on('pagecontainershow', '#onePage", function(event, ui) { instead of I'd consider that a win at this point (which is sad). Realistically if my projects weren't so involved, I'd switch from jQuery Mobile to something else, after hearing this "resolution". I've been working with jQuery Mobile since alpha (I did a research project on it while it was in alpha when I was in college), and with the 1.4 changes I just can barely stand it now. |
My apologies to not also responding to this thread sooner. The proposed solution, although workable for some projects, is still rather clunky & I don’t have much to add to what Jon & Mick have already said. I’ve already moved on. I still view jQueryMobile as very valuable for smaller projects, that can comfortably live within the constraints that come with it. Regards, Sam From: Mick Tindall +1 for the above post. At this point, I just with the pagecontainer events were delegate-able. If I could do $(document).on('pagecontainershow', '#onePage", function(event, ui) { instead of I'd consider that a win at this point (which is sad). Realistically if my projects weren't so involved.I'd switch from jQuery Mobile to something else, after hearing this "resolution" — |
With pagecreate event it was possible to lauch event when jqm page loaded the first page. |
@ottoville if you look at what i posted you will see that @Palestinian switch and if statements have in all reality no perf impact please see http://jsperf.com/switch-and-if-perf while the switch and if are of course slower all three tests are in the range of 500 MILLION operations per second I can 100% promise this will not impact your application. In fact delegated events in the way page events were generally bound to before have to perform this same logic under the hood anyway. In a delegated event you listen to the event on the parent then using an if statement it is checked if the target matches the page you bound to. @simsam7 @jtara i fail to see how the onPage solution differs from from what we originally had with page events you bind to them in the same way the ONLY difference is you move the word page from the event name to the method name?? |
What about pagebeforeshow event, docs say that it is deprecated. That event is also triggered on initial load but new pagecontainerbeforeshow does not trigger on initial load. |
@ottoville beforeshow does fire on initial load. http://jqmtricks.wordpress.com/2014/03/26/jquery-mobile-page-events/ |
There are some bug with these new events, please have a look this jsfiddle It is possible to register event listeners only after DOM has been fully loaded. I dont see any reason for that, it is against event listening model. |
@Palestinian |
@ottoville Attach pagecontainer events listeners to |
@arschmitz Once again, thanks for the clarification. Btw, I have tested the |
@Palestinian No problem we want this to work and be as convenient as possible however we also have to make an api that makes sense. the onPage plugin depends on changes to JQM that are currently only in a branch this branch includes demos on use of both the onPage plugin and the event debugger once this branch is ready I will post a link here. This should be pretty soon finishing this and getting 1.4.3 out is my current top priority. |
It is weird that it is not possible to attach pagecontainerbeforeshow listener on document.body. As the documentation states, the page container === body element, so I dont see why The old beforeshow event triggered on page, so it was possible to have reference to page by using 'this' or evt.target. The new pagecontainerbeforeshow triggers on page container. I cannot see reference to page itself in event attributes. It is possible to use $(this).pagecontainer( "getActivePage" )[0], but that does not work on initial load. So how to have reference on page that triggered pagecontainerbeforeshow, when having a initial load? |
@ottoville please read the updates above we are planning on making #7283 (comment) you will reference the to and from page via the ui param passed to the callback as far as the body element you should be able to bind to the body for these events just fine if you can produce an example showing other wise in jsbin please open an issue for it. Remember if you bind in this way too soon the body may not exist yet, and since you are not delegating your handler you wont get the event. If you do it in document ready you wont get the initial one because you are binding too late. |
To make sure all former page events have a page container counterpart, and that this counterpart has both a toPage and prevPage prop on the ui object Also add a demo of how to debug pagecontainer events Fixes jquery-archivegh-7063 Fixes jquery-archivegh-7283 Fixes jquery-archivegh-7176 Closes jquery-archivegh-7285
This is not a bug request, i would like to raise an design / architectureal issue. Starting in JQM 1.4 onwards, page life cycle events (e.g. pageshow) are deprecated in favour of 'pagecontainershow'. Please consider the case below, where i think it's not a nice replacement.
We use JQM in a rather big project with several developers, where we try to split up the app in functional "modules". For this we also use separated files to give the app a certain structure. It was very convenient to have a way to implement the page specific handlers on the page itself for actions like templating and custom JavaScript preparations, etc...
Now, with the container i still can do that, but i must control the logic centrally and then dispatch again to the page module... Architectural wise, that's a strange approach...
I would love to see again a way to bind "life cycle" logic to a page again. Since programmers will work on pages as their logical work unit and they want to control the life cycle on that logical work unit...
Cheers,
Patrick
The text was updated successfully, but these errors were encountered: