azicchetti / jquerymobile-router

A router/controller for jquery mobile. Also adds support for client-side parameters in the hash part of the url. The routes handles regexp based routes. This plugin can be used alone or (better) with Backbone.js or Spine.js, because it's originally meant to replace their router with something integrated with jQM.
GNU General Public License v2.0
402 stars 69 forks source link

e.preventDefault() on a re-routing system #83

Open mreis1 opened 9 years ago

mreis1 commented 9 years ago

As specified at the documentation it's possible to preventDefault the $.mobile.pageChange() and resolve it as soon as we want.

So, because my application keeps most of it's UI structure in all diferent views, like header and sidebar, I decided to create the following approach.

at index.html

<div data-role="page" class="type-interior" id="page1">
   <div class="header">foo</div>
   <div class="placeholder">bar</div>
</div>
<div data-role="page" class="type-interior" id="page2">
      <div class="header">foo</div>
      <div class="placeholder">bar</div>
</div>
<div data-role="page" class="type-interior" id="page">
          <h1>This page is never shown</h1>

            I intersect any changePages to this router and based on the last active page(#page1 or #page2) I update the content into the next.

          <!--  -->
</div>

at router.js

var myRoutes = [
    //...other routers to other pages like #login ...
    { "#page":      { handler: "pageBc", events: "bC", argsre: true }},
    //views will be toggled between this 2 pages
    { "#page1":      { handler: "dynamicView", events: "bC", argsre: true }},
    { "#page2":      { handler: "dynamicView", events: "bC", argsre: true }},
];

var myHandlers = {
pageBc: function(type,match,ui,page,e){
        e.preventDefault();
        ui.toPage = pageChanger.getNextPage();
        // ui.options.changeHash = "true";
        // ui.options.dataUrl = ui.toPage;
        ui.bCDeferred.resolve();
        console.log("this is an hub view, you are going to be...");
        console.log("...redirected to another view");
    },
    dynamicView: function(type,match,ui,page,e){
        e.preventDefault();
        var params = approuter.getParams(ui["options"]["dataUrl"]);
        var p = params["id"];
        switch (p)
        {
            case "dog":
                console.log("dog");
                myapp.fetchDogs().done(function(data){
                         myApp.renderDogs(data).done(function(){
                            //ok, data is fetched and rendered. We are ready to show the view
                             ui.bCDeferred.resolve();
                         });
                });
                break;
         // ...other possible params passed as id #page?id=dog, #page?id=cats
}

the pageChanger monitors the last JQM page where html data referencing the view was appended. For example. if we appended data into "#page1 .placeholder" when transtioning to #page?id=dogs, if we change to #page?id=cats our target view will be #page2 (which is response from the pageChanger.getNextPage())

var PageHandler = function(){
    var currentPage = "#page1";
    this.getCurrentPage = function(){
        return currentPage;
    };
    this.getNextPage = function(){
        return updatePage();
    };
    var updatePage = function(){
        if (currentPage == "#page1"){
            currentPage = "#page2";
        } else {
            currentPage = "#page1";
        }
        return currentPage;
    };
};

var pageChanger = new PageHandler();

This solution is great because it solves the visual problem of transitioning to the same page where most of the time we see:

<div data-role="dog" class="type-interior" id="page2">
      <div class="header">foo</div>
      <div class="content">
           <ul class="sidebar">
                <li>
               <a href="#dogs"></a>
                </li>
                <li>
               <a href="#cats"></a>
                </li>
               <!-- other links -->
           </ul>
          <placeholder></placeholder></div>
</div>
<div data-role="cats" class="type-interior" id="page2">
     <!--same structure of dogs and all other sidebar items -->
</div>

Any help please?

mreis1 commented 9 years ago

After digging into the problem by starting a simple project to ensure that only essencial code was part of the content I realize that the problem report above is not, somehow, caused by my code.

I did this Demo where I achieved the desired task https://github.com/mreis1/jqmrouter-singlepage

Anyway during the development of that demo i detected another problem with deferred transitions. For example, If we click on link whose router handler is preventing the page transition for something like 2 seconds (just an example), If I click on second link during the those 2 seconds we'll face one of the following problems: a) if the second link takes lesser than 2 seconds to navigate to the target page we will be redirected to the second link and when the first link gets resolved, we are taken to it's content. b) if the second link takes longer than 2 seconds the problem will be the opposite. First we are taken to the first page and then right after to the second page

Probably the default desired behavior would be cancel any ongoing deferreds.