jquery-archive / jquery-mobile

jQuery Mobile Framework
https://jquerymobile.com
Other
9.68k stars 2.4k forks source link

Parameters for pages broken in 1.0b1 #2082

Closed azicchetti closed 13 years ago

azicchetti commented 13 years ago

jQuery Mobile should support passing parameters between internal pages, for example

page2?param=value&param2=value2

issue #471 (this feature request) was marked as closed but the current implementation seems broken.

Clicking on an anchor with such a link triggers a strange behavior as can be seen at this test page: http://www.tracemyworld.com/abghqq/jqmproblem.html

jQuery Mobile creates a new page div with the correct data-url but with the content of the currently displayed page, not the target one.

I think it's appropriate to attach a small request... having parameters is like a dream cause we can bookmark pages that renders dynamically client side, but the url is absolutely ugly with those param=value&etc, it's still web 1.0 style. Can't we do something better? We need 'restful' urls here.

jQuery Mobile should support at least the following url schemas for internal pages:

page?foo=bar&bar=foo

page/foo/bar

The problem is that we can get confused with the urls pointing to an external page loaded via ajax, but we may distinguish between internal urls and external ones by looking at the first character after the #:

Taking a live example from the website:

http://jquerymobile.com/demos/1.0b1/#/demos/1.0b1/docs/pages/docs-pages.html http://jquerymobile.com/demos/1.0b1/#../../demos/1.0b1/docs/pages/docs-pages.html these are clearly ajax pages because #/demos/etc... is a path.

http://jquerymobile.com/demos/1.0b1/#internalPage/1.0b1/page/10 is a fantasy url pointing to an internalPage that support restul-style parameters /1.0b1/page/10

I know this is a big game changer, but it's vital for the future of the framework (tons of requests about parametrised urls have been posted on the forum and here, developers need them!) to decide these things before the 1.0 release.

EDIT: ... or we can take a leap into the unknown and change the url types to include the "bang" for ajax pages (to better support crawlers). This is not needed by the framework, since it can handle the proposed url types without much effort and without the "bang", but the "!" sign may be useful for humans to immediately tell if an url is ajax based or internal. In addition, eliminating these "gray areas" by making clear that an url is not ajax based could solve a lot of potential problems now and in the future throughout the framework.

http://jquerymobile.com/demos/1.0b1/#!/demos/1.0b1/docs/pages/docs-pages.html (ajax) vs http://jquerymobile.com/demos/1.0b1/#demos/pages/10 (internal with params)

We can also do viceversa but the google bot wouldn't be happy...

Thanks.

scottjehl commented 13 years ago

This is an interesting feature request, but we're not sure we understand the use for query strings directed at a subsection of a document, rather than a server resource (a separate url). It seems that using separate physical pages would be better suited for this style of dynamic page content, whereas jqm's multipage documents are just a simple mechanism for displaying static anchored sections of a document as a view.

If you must use multipage setup for this, you could probably manage your application state using a JavaScript object throughout the session, instead of adding query strings to the hash. Is there a reason you could not do this currently?

As for the bang suggestion, we're moving towards pushState soon to clean up our URLs across the board. In the process, we'll be continuing to advise that developers consider developing sites using externally referenced pages instead of multipages (like you'd build any standard website), since multipage documents were always meant for simple static scenarios where each page feels like a sub-section of a document, were you to view it without CSS/JS.

let me know if I'm missing the point of what you're asking for. Perhaps I'm not getting the real benefit of passing query strings to sub-portions of a document.

azicchetti commented 13 years ago

I'm sorry I didn't write the purpose in the previous post.

All the applications and websites I've done in jQm until now use an internal object to keep track of things in order to dynamically generate on the client different content based upon user selections. In this scenario the server only provides the content as json objects and templating is done on the client.

This perfectly works for applications, but websites pages are not bookmarkable because I can't "encode" the application state in the url. As a result, I've to write some server-side code to generate the html page and load it via ajax. I'd really like to reuse the same code to build both the application and the mobile website and cut off the costs for my customers.

I think that having a reliable way to put purely client-side states in the url is a key point for the whole framework and a really wanted feature, as we can see in the forum. Fixing the current bug and supporting urls like #internalPage?restOfTheUrlWhereWeCanEncodeParameters should suffice for most of us, so that we can build our own MVC "router/controller" (have you ever seen the beauty of the backbone.js controller? I'd love to see it natively implemented in jQm and be pagebeforeshow / pageshow aware).

Thank you and keep up with the good work!

scottjehl commented 13 years ago

Thanks. Yeah this is a tough one, as we'd probably recommend using separate pages to build this sort of app, loading each page with Ajax as they're needed. That's the only way to truly achieve the broad browser support that jQM aims to provide, and building that way comes with all the benefits you describe, such as truly addressable pages that represent real js-independent resources on your site, and it's cleaner to manage as well.

That said, there's no reason you can't optimize a site that's built with separate pages so that it works even faster in capable browsers. You might choose to fetch all subsequent pages from a local data store, for instance.

I'm just still unsure that passing params to internal divs is a solution we'd recommend, but I can leave this open as a feature request. thanks again.

IgitBuh commented 13 years ago

I would very, very, very much appreciate the possibility to pass parameters to pages in the url. azicchetti linked to the issue where I posted previously and described the use case it's required for. To avoid copy&paste, please read my two last postings here: https://github.com/jquery/jquery-mobile/issues/471 If you search the jqm forums you'll find several threads where people try to find a solution. There's definitely a need for it. Please understand that it's an essential part of web development to pass parameters to pages. It's not some kind of fancy feature it's a basic requirement. Thank you.

azicchetti commented 13 years ago

I don't mind if jqm doesn't officially support this feature, I just need a solid basis to build a plugin upon.

With the latest test build of jqm, if you:

you can achieve our beloved feature of supporting parameters in the hash portion of the url. In the issue #471 I've linked a small project (whose goal is completely different) where I use this technique, but it doesn't work with 1.0b1.

I don't have time to debug at the moment, but I'm afraid that this thing isn't sound enough to resist across jqm updates... Any hint from the official developers? Can we rely on something like this for future releases?

Thanks

scottjehl commented 13 years ago

Hi folks.

Thanks for staying on top of us on this. While we're still not convinced that we'll want to recommend or implement this feature in an officially-supported sense (due to its JS-dependence, its use of local anchors in a non-standard way, and the fact that external pages handle dynamic content well already), there's probably a way to do what you're trying to do already.

One way to do it is similar to the approach @azicchetti described above, and I can't imagine it'd regress in upcoming releases. Something like this could probably do what you're trying to do...

$( "a" ).bind( "click", function(){
    var href    = $( this ).attr( "href" ).match( /#([^\?]+)(\?.*$)/ ),
        pageid  = RegExp.$1, // should contain the page id without the "#"
        qstring = RegExp.$2; // Should contain the query string

    $( ":jqmData(role='page')[id^='" + pageid + "']" ).jqmData( "url", pageid + qstring );
});

Here's a demo page that demonstrates:

Again, we'd recommend structuring things differently to use external pages for dynamic content like this - served as html or otherwise - instead of a multipage document. We're planning to blog about some ways to do this in the coming weeks. Hope this helps!

jbrooksuk commented 13 years ago

Your demo doesn't work for me. At least, clicking the button labelled "show page two" doesn't take me to #two

Come on, this is a massively needed part of jQM. How do you expect us to keep links bookmarkable, and serve up AJAX content?

scottjehl commented 13 years ago

Ah, thanks, you're right, sorry. Page 2 does get the query-string data-url applied if you inspect the DOM at least. I'll post a revision in a few...

jbrooksuk commented 13 years ago

I noticed the URL does seem to change, just the page didn't, so it's not quite a fix yet :(

scottjehl commented 13 years ago

By the way, what if you simply applied a different attribute to the page in question, instead of affecting its data-url? For example, if you changed the second to last line in the example above to something like this:

$( ":jqmData(role='page')[id^='" + pageid + "']" ).jqmData( "url-qstring", qstring );

...then you could retrieve that q string by binding to that page's pagebeforeshow event and getting its elem.jqmData("url-qstring");

jbrooksuk commented 13 years ago

But how could I link to this page? The parameters need to be in the URL for the AJAX.

And no, I cannot have a page for every single output of the parameter.

azicchetti commented 13 years ago

My implementation is similar and supports local pages in a multipage template but also ajax pages (basically, once you've fetched an ajax page, it won't be fetched again just because its query string is changed). This code works if the anchor declares data-params="true"

    function changePageDataUrl(href,isHash){
            var     HASH_QUERY_STRING_RE=/(.+?)(?:[?\/](.*))?$/,
                    QUERY_STRING_RE=/(.+?)(?:[?](.*))?$/,
                    qs=isHash?HASH_QUERY_STRING_RE:QUERY_STRING_RE,
                    res=href.match(qs), page=res[1]
            ;
            $(':jqmData(url^="'+ page +'")').each(function(){
                    var dataUrlQS=$(this).attr("data-url").match(qs);
                    if (dataUrlQS[1]==page){
                            $(this).attr("data-url",res[0]).jqmData("url",res[0]);
                    }
            });
    }

            $("a[data-params]").live("click",function(e){
                    var     PROTOCOL_HOST_RE=/(http?|ftp|file):\/\/[^\/]*/,
                            href
                    ;
                    href=$(this).attr("href");
                    if (href.charAt(0)=="#"){
                            if (href.length<2) return;
                            changePageDataUrl(href.slice(1),true);
                    } else {
                            href=this.href.replace(PROTOCOL_HOST_RE,"");
                            changePageDataUrl(href);
                    }
            });
                    // we have to route and provide support to the initial url
                    if (window.location.hash.length>1){
                            $(document).ready(function(){
                                    changePageDataUrl(window.location.hash.slice(1),true);
                            });
                    }
scottjehl commented 13 years ago

jbrooksuk, please give me the benefit of the doubt here so I can help you work through this. I've taken a morning's worth of attention away from blocking issues to try and help you solve a problem that is very particular to the way you've chosen to architect your site. This approach does not follow any workflows we've recommended in the docs and examples, so a custom workaround here and there should be expected.

I'm trying to create a demo for you, but it's not easy, as we never intended the framework to use multipages in this way, for a number of reasons.

"How do you expect us to keep links bookmarkable, and serve up AJAX content?"

We recommend using separate pages/urls for this, just like you'd build any other website or web-based app. In fact, we recommend that you do not use multipages in the way this issue requests because doing so will actually break -- not preserve -- bookmarking to those sub-sections of the page in non-js environments, not to mention search engine crawlers, and otherwise.

Your page source contains no IDs that match the hrefs that are supposedly referencing. jQM tends to operate on top of an already-functional website, enhancing it in certain areas, but in no way enforcing that content only be available via JavaScript.

Multi-page documents are meant as a convenience for displaying simple, static, sections of a page that would otherwise make sense as portions of a single document, were it to be viewed in full.

We're trying to direct developers to use features that have already been carefully architected to support dynamic content in a much more accessible manner. jQM already has workflows that you can use to serve pages with dynamic content, and using them as documented will make for a very smooth upgrade into non-hash-based URLs when we soon implement history.pushstate.

As time permits, I will be trying and work out a demo for you, and it'd be great if any other stakeholders in this issue could do the same.

Thanks.

scottjehl commented 13 years ago

Thanks, @azicchetti! Hopefully this will help.

jbrooksuk commented 13 years ago

@azicchetti I'm unable to get your implementation to work. Can you provide a demo at all please?

azicchetti commented 13 years ago

there's a demo you can download at https://github.com/azicchetti/jquerymobile-router Needs the test version of jqm.

Il giorno 21/lug/2011 15:00, "jbrooksuk" < reply@reply.github.com> ha scritto:

@azicchetti I'm unable to get your implementation to work. Can you provide a demo at all please?

Reply to this email directly or view it on GitHub: https://github.com/jquery/jquery-mobile/issues/2082#issuecomment-1623368

balla commented 13 years ago

Too bad to see this issue closed.. I've been waiting/looking for such a feature for long time.

Since most of my developments with jqm are coupled with Phonegap, getting pages from server can become a very awkward process as well as saving already rendered pages. In particular when you start targeting multi-language applications, the overall page number you have to deal with easily increases and their management might become unnecessary complicated.

The server should not be stressed with that, when you start dealing with large number of pages the best way is just to let the server deliver json contents and let the client do the the rendering work. Url parameters are not mandatory for such an approach, however they are very useful to avoid attaching unnecessary events and allow to let your pages bookmarkable.

I believe that letting the client easily rebuild an application status by means of url parameters is a fundamental issue for this framework.

IgitBuh commented 13 years ago

Thank you balla for posting your interest as well! I think it's good if more people show their need in such a feature. Please, jQM crew, allow the developers to decide for themselves if they want to use page parameters or not. Since it's part of web developing I think many will use it. Those who doesn't want or need to to use it of course don't have to. I don't see the disadvantage of giving the possibility so that everyone can have his own decision.

andyl commented 13 years ago

Bookmarkable page parameters should be supported in jQM. I hacked a workaround using localStorage. But its not bookmarkable.

azicchetti commented 13 years ago

You have to support this kind of urls by yourself, using the "hack" described in the jQuery Mobile documentation: http://jquerymobile.com/demos/1.0rc1/docs/pages/page-dynamic.html

You may want to use a plugin that helps you doing this (and other nice things): https://github.com/azicchetti/jquerymobile-router

andyl commented 13 years ago

I'll add these comments for clarity - per the suggestion of @jblas - in jQM, I'd like to use a href like this:

<a href="#basepage?city=a&state=b">link</a>

When you click on this link, jQM should:

The problem I have is inconsistent behavior on different browsers, especially when clicking multiple links with different query strings...

Some have suggested that the solution is to render all possible pages on the server, each with their own unique data-url='#hash?key1=value1&key2=value2'.

That approach would not work for me.

IMHO solving this issue will benefit many developers.

jblas commented 13 years ago

Just an FYI, I know that @azicchetti has written a plugin for handling query param passing between pages:

https://github.com/azicchetti/jquerymobile-router

We can't officially support page params for 1.0, so I also wrote a more barebones version here:

https://github.com/jblas/jquery-mobile-plugins/tree/master/page-params

folks can either use it as is, or copy it and bend it to their will.

johnbender commented 12 years ago

I wanted to clarify the above issue reference. Reloading the initial page should also handle query params.