0

I made my web site using jquery mobile multi page template. When accessing this site using Chrome on a desktop computer my js variables comics and checkedItems persist when changing pages. However, when I visit the site on a mobile device it doesn't appear that these arrays are keeping their values. What about mobile devices is not the same as desktop browsers? Do I have to store these in local storage? Here is the js:

var comics = new Array();
var checkedItems = new Array();
var url = "http://www.midtowncomics.com/rssfeed/rssallnewrelease.xml";
var cat = "";
var zip;
var lat;
var long;

$(document).on("pageshow","#catpage",function(){
  $("li").click(function(e){
    cat = e.target.id;
  });                       
});

$(document).on("pagebeforeshow","#totalpage",function(){
  if(checkedItems) {
      var output = "";
      var total = 0.0;
      $.each(checkedItems, function(itemIndex, checkedItem){
        var price = 0.0;
        var title = checkedItem;

        $.each(comics, function(comicIndex, comic){

          if(checkedItem === comic.title) {
            price = parseFloat(comic.price);
          }

        });

        total = total + price;

        output += '<p>' + title + ' - $' + price + '</p>'; 

      });

      total = total.toFixed(2);

      output += '<h1>Total: $' + total + '</h1>';
      $('#comicPriceList').html(output);
    }                     
});

$(document).on("pagebeforeshow","#emailpage",function(){
  if(checkedItems) {
      var output = "";
      var total = 0.0;
      $.each(checkedItems, function(itemIndex, checkedItem){
        var price = 0.0;
        var title = checkedItem;

        $.each(comics, function(comicIndex, comic){

          if(checkedItem === comic.title) {
            price = parseFloat(comic.price);
          }

        });

        total = total + price;

        output += '<p>' + title + ' - $' + price + '</p>'; 

      });

      total = total.toFixed(2);

      output += '<h1>Total: $' + total + '</h1>';
      $('#comicEmailList').html(output);
    }                     
});

function sendMail() {
  var list = $('#comicEmailList').html();

  var address = $('#emailAddress')[0].value;

  $.ajax({
  type: "POST",
  url: "https://mandrillapp.com/api/1.0/messages/send.json",
  data: {
    'key': 'uZEnSwFe1NeKxIrYs54aNw',
    'message': {
      'from_email': address,
      'to': [
          {
            'email': address,
            'type': 'to'
          }
        ],
      'autotext': 'true',
      'subject': "Your Pull List",
      'html': list
    }
  }
 }).done(function(response) {
   alert('Email Sent!');
 });
}

$(document).on("pagebeforeshow", "#titlepage", function(){

 document.getElementById("categoryTitle").innerHTML = cat;

    var output = "";
    $.each(comics, function(index, comic){
      if(cat == comic.category)
      {

        output += '<label onClick="updateCheckList(event)" for="' + comic.title + '">' + comic.title + " - Publisher: " + comic.mfg + " - $" + comic.price + '</label>';
        if($.inArray(comic.title, checkedItems) > -1) {
          output += '<input type="checkbox" name="collectable" id="' + comic.title + '" value="' + comic.title + '" checked>';
        } else {
          output += '<input type="checkbox" name="collectable" id="' + comic.title + '" value="' + comic.title + '">';
        }

      }  
    });
    $('#titlelist').html(output);
    $('#titlelist').trigger('create');
});

function updateCheckList(event) {
  var item = event.target.nextSibling;
  if(item.checked) {
    var i = checkedItems.indexOf(item.id);
    if(i != -1) {
        checkedItems.splice(i, 1);
    }
  } else {
    checkedItems[checkedItems.length] = item.id;
  }
}

$(document).on("pagecreate","#homepage",function(){
  $("a").on("swipeleft",function(){
    alert("You swiped left!");
  });      

  $.ajax({
    url: 'http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=999&callback=?&q=' + encodeURIComponent(url),
    dataType: 'json',
    success: function(data) {
      var items = data.responseData.feed.entries;
      var prev = "";
      var output = "";
      $.each(items, function(index, value){

        var comic = {};

        var content = value.content;

        var categoryPattern = /Category:.+.<\//;
        var categoryArray = categoryPattern.exec(content);
        var category = categoryArray[0];
        category = category.substring(17,category.length-2);
        comic.category = category;

        if(prev != category)
        {
          output += '<li><a href="#titlepage" id="' + category + '" data-transition="flip">' + category + '</a></li>';
          prev = category;
        }  

        var title = value.title; 
        comic.title = title;

        var pricePattern = /\$.+.<\//;
        var priceArray = pricePattern.exec(content);
        var price = priceArray[0];
        price = price.substring(2,price.length-2);
        comic.price = price;

        var mfgPattern = /Manufacturer:.+.<\//;
        var mfgArray = mfgPattern.exec(content);
        var mfg = mfgArray[0];
        mfg = mfg.substring(21,mfg.length-2);
        comic.mfg = mfg;

        var pubDatePattern = /Release Date:.+.<\//;
        var pubDateArray = pubDatePattern.exec(content);
        var pubDate = pubDateArray[0];
        pubDate = pubDate.substring(21,pubDate.length-2);
        comic.pubDate = pubDate;

        var linkPattern = /http.+/;
        var linkArray = linkPattern.exec(content);
        var link = linkArray[0];
        link = link.substring(0,link.length-8);
        comic.link = link;
        comics[index] = comic;
      });
      document.getElementById("releasesButton").innerHTML = "Releases For: " + comics[0].pubDate;
      $('#catlist').html(output);
      $('#releasesButton').removeClass('ui-disabled');
    }
  });

});

function setItemList() {
    if(checkedItems) {
      var output = "";
      $.each(checkedItems, function(index, item){

         output += '<p>' + item + '</p>'; 

      });
      $('#itemList').html(output);
    }
}

$(document).on( 'taphold', 'label', tapholdHandler )

function tapholdHandler( event ){
  var title = event.target.nextSibling.id;

  $.each(comics, function(index, comic){
      if(title == comic.title)
      {
        window.open(comic.link);
      }  
    });
};

function getLocation() {
  if ( navigator.geolocation ) {
        function success(pos) {
            // Location found, show map with these coordinates
            //drawMap(new google.maps.LatLng(pos.coords.latitude, pos.coords.longitude));
            lat = pos.coords.latitude;
            long = pos.coords.longitude;

            url = "http://nominatim.openstreetmap.org/reverse?format=json&lat=" + lat + "&lon=" + long + "&addressdetails=1"
            $.ajax({
              url: url,
              dataType: 'jsonp',
              jsonp: 'json_callback',
              cache: true,
              success: function(data) {
                zip = data.address.postcode;
                $("#fname").val(zip);
              }
            });
        }
        function fail(pos) {
        }  
        navigator.geolocation.getCurrentPosition(success, fail, {maximumAge: 500000, enableHighAccuracy:true, timeout: 6000});
    }
}

var map;
var service;
var infowindow;

$(document).on("pageshow","#totalpage",function(){

  var pyrmont = new google.maps.LatLng(lat,long);

  map = new google.maps.Map(document.getElementById('map-canvas'), {
      center: pyrmont,
      zoom: 15
    });

  var request = {
    location: pyrmont,
    radius: '500',
    query: 'comic book shop',
    rankBy: google.maps.places.RankBy.DISTANCE
  };

  infowindow = new google.maps.InfoWindow();
  service = new google.maps.places.PlacesService(map);
  service.textSearch(request, callback);

});

function callback(results, status) {
  if (status == google.maps.places.PlacesServiceStatus.OK) {
    var output = "";
    for (var i = 0; i < results.length; i++) {
      var place = results[i];
      if(place.name) {
        var name = place.name;
        var address = place.formatted_address;
        output += '<p>' + name + '\n' + address + '\n</p>'; 
      }
    }
    $('#placesList').html(output);
  }
}

function createMarker(place) {
  var placeLoc = place.geometry.location;
  var marker = new google.maps.Marker({
    map: map,
    position: place.geometry.location
  });

  google.maps.event.addListener(marker, 'click', function() {
    infowindow.setContent(place.name);
    infowindow.open(map, this);
  });
}

And the HTML:

<!DOCTYPE html>
<html>
<head>

<link rel="shortcut icon" href="icon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="themes/Test.min.css" />
<link rel="stylesheet" href="themes/jquery.mobile.icons.min.css" />
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.3/jquery.mobile.structure-1.4.3.min.css" />
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.4.3/jquery.mobile-1.4.3.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=places"></script>
<script src="rsslist.js"></script>
<style>
      html, body, #map-canvas {
        height: 100%;
        margin: 0px;
        padding: 0px
      }
</style>

</head>
<body>

<div data-role="page" id="homepage">
  <div data-role="panel" id="myPanel" data-dismissible="false">
    <h2>Your Pull List</h2>
    <div id="itemList"></div>
  </div>

  <div data-role="header" data-position="fixed">
    <h1>Weekly Pull List</h1>
    <a href="#myPanel" onclick="setItemList()" class="ui-alt-icon ui-btn ui-corner-all ui-shadow ui-icon-bars ui-btn-icon-notext" data-transition="slide"></a>
  </div>

  <div data-role="main" class="ui-content">
    <a href="#catpage" id="releasesButton" class="ui-disabled ui-alt-icon ui-btn ui-corner-all ui-shadow ui-icon-bars ui-btn-icon-right" data-transition="flip">Releases For: 

</a>

    <div data-role="collapsible">
      <h1>Total Cost Calculator</h1>
      <a href="#" onClick="getLocation()" class="ui-alt-icon ui-btn ui-corner-all ui-shadow ui-icon-location ui-btn-icon-right" data-transition="slideup">Use Location</a>
      <p>OR ENTER ZIP CODE</p>
      <input type="number" name="fname" id="fname">
      <a href="#totalpage" class="ui-alt-icon ui-btn ui-corner-all ui-shadow ui-icon-shop ui-btn-icon-right" data-transition="slideup">Calculate Total</a>
    </div>

  </div>

  <div data-role="footer" data-position="fixed">
    <h1>Dylan and Adam's Comic List</h1>
    <h5>Powered by midtowncomics.com</h5>
  </div>

</div> 

<div data-role="page" id="titlepage">
  <div data-role="header" data-position="fixed">
    <h1 id="categoryTitle">Weekly Pull List 2</h1>
    <a href="#catpage" class="ui-alt-icon ui-btn ui-corner-all ui-shadow ui-icon-back ui-btn-icon-left" data-transition="flip">Go Back</a>
    <a href="#homepage" class="ui-alt-icon ui-btn ui-corner-all ui-shadow ui-icon-home ui-btn-icon-left" data-transition="flip">Go Home</a>
    <!--<a href="#" class="ui-alt-icon ui-btn ui-corner-all ui-shadow ui-icon-search ui-btn-icon-left" onclick="myFunction()">Search</a>-->
  </div>

  <div data-role="main" class="ui-content">
    <form class="ui-filterable">
      <input id="myFilter" data-type="search" placeholder="e.g. Title">
    </form>

    <fieldset data-role="controlgroup" data-filter="true" data-input="#myFilter" id="titlelist">
      <label for="X-Men">X-Men</label>
      <input type="checkbox" name="collectable" id="X-Men" value="X-Men">
      <label for="Spider-Man">Spider-Man</label>
      <input type="checkbox" name="collectable" id="Spider-Man" value="Spider-Man">
      <label for="Avengers">Avengers</label>
      <input type="checkbox" name="collectable" id="Avengers" value="Avengers"> 
    </fieldset>
  </div>

  <div data-role="footer" data-position="fixed">
    <h1>Dylan and Adam's Comic List</h1>
    <h5>Powered by midtowncomics.com</h5>
  </div>
</div>

<div data-role="page" id="totalpage">
  <div data-role="header" data-position="fixed">
    <h1>Total Price</h1>
    <a href="#homepage" class="ui-alt-icon ui-btn ui-corner-all ui-shadow ui-icon-home ui-btn-icon-left" data-transition="slidedown">Go Home</a>
    <a href="#emailpage" class="ui-alt-icon ui-btn ui-corner-all ui-shadow ui-icon-mail ui-btn-icon-left" data-transition="flip">Email List</a>
  </div>

  <div id="comicPriceList" data-role="main" class="ui-content"> 
    <p>Total: </p>
  </div>
  <h1>Nearby Comic Book Shops: </h1>
  <div id="placesList" data-role="content" class="ui-content"></div>

  <div id="content">
     <div id="map-canvas" style="height:100%"></div>
  </div>

  <div data-role="footer" data-position="fixed">
    <h1>Dylan and Adam's Comic List</h1>
    <h5>Powered by midtowncomics.com</h5>
  </div>
</div>

<div data-role="page" id="emailpage">
  <div data-role="header" data-position="fixed">
    <h1>Email List</h1>
    <a href="#totalpage" class="ui-alt-icon ui-btn ui-corner-all ui-shadow ui-icon-back ui-btn-icon-left" data-transition="flip">Go Back</a>
    <a href="#totalpage" onClick="sendMail()" class="ui-alt-icon ui-btn ui-corner-all ui-shadow ui-icon-mail ui-btn-icon-left" data-transition="flip">Send</a>
  </div>

  <div id="comicPriceList" data-role="main" class="ui-content"> 
    <label for="basic">Email Address:</label>
    <input type="email" name="name" id="emailAddress" value="" />
    <div id="comicEmailList"></div>
  </div>

  <div data-role="footer" data-position="fixed">
    <h1>Dylan and Adam's Comic List</h1>
    <h5>Powered by midtowncomics.com</h5>
  </div>
</div>

<div data-role="page" id="catpage">
  <div data-role="header" data-position="fixed">
    <h1>Catagories</h1>
    <a href="#homepage" class="ui-alt-icon ui-btn ui-corner-all ui-shadow ui-icon-home ui-btn-icon-left" data-transition="flip">Go Home</a>
  </div>

  <div data-role="main" class="ui-content">
    <form class="ui-filterable">
      <input id="myFilter2" data-type="search" placeholder="e.g. Catagories">
    </form>
    <ul data-role="listview" id="catlist" data-filter="true" data-input="#myFilter2" data-inset="true">
      <li><a href="#titlepage" data-transition="flip">Marvel</a></li>
    </ul>
  </div>

  <div data-role="footer" data-position="fixed">
    <h1>Dylan and Adam's Comic List</h1>
    <h5>Powered by midtowncomics.com</h5>
  </div>
</div>

</body>
</html>
Adam6806
  • 87
  • 10
  • Is your ajax request working properly on your phone? I know it's a pain to debug but perhaps a simple alert in the success callback will illustrate whether it's completing or not.You perhaps have a setting on your desktop that disables `same-origin-policy` however your phone might not have that. Such functionality only works once you "wrap" it with Cordova/PhoneGap for example. In the mean-time or if you're not going to "wrap" it at all, you may well need to JSONP the ajax command. http://learn.jquery.com/ajax/working-with-jsonp/ – Rob Schmuecker Aug 03 '14 at 21:59
  • @RobSchmuecker All of the ajax calls I have work great on my mobile device. The Ajax calls aren't the issue. The issue is the persistance of the js variables comics and checkedItems between the JQM pages. Those arrays persist just fine on my desktop computer but not in my android browser. – Adam6806 Aug 03 '14 at 22:10
  • ok good, just though perhaps since the only way I could see it getting populated was via Ajax so thought that might be the issue. If it's a multi-page site and it isn't resolving to a new load of the page but purely via `#` navigation, then it shouldn't be losing variable state at all. The JS file you mention, where is that in your HTML? – Rob Schmuecker Aug 03 '14 at 22:18
  • @RobSchmuecker It's the last script listed. `` – Adam6806 Aug 03 '14 at 22:25
  • It's working on iPad 2, safari. – Omar Aug 03 '14 at 22:36
  • I don't have a PC to test it, but I guess the problem the `onclick="setItems()` function attached to panel's button. Instead of using inline js, add click listener to that button on `pagecreate` of homepage. – Omar Aug 03 '14 at 23:00
  • @Omar I don't think that's the issue. The same problem arises everywhere that the js accesses the checkedItems array. For example the total price page, the email page, and when the check boxes for already checked items are set to checked. So far I've tested the native android browser, chrome for android, and opera for android. Some times I can get one item to show up but not consistently and never the whole page. This seems very strange. Especially since it works perfectly on a desktop. – Adam6806 Aug 03 '14 at 23:04
  • Ok, the problem is in checkboxes in title page. You're using inline js too, where you should listen to `change` event instead. On desktop, `label` receives `click`, however, on mobiles it looks like it doesn't. Your solution is `$(document).on("pagecreate", "#titlepage", function (){ $("[type=checkbox]").on("change", updateCheckList); });`. Another note, you need to modify the way you create controlgroup, check this answer http://stackoverflow.com/a/20692597/1771795 – Omar Aug 03 '14 at 23:16
  • @Omar so you're saying the issue here is that onClick methods don't trigger on mobile platforms? – Adam6806 Aug 03 '14 at 23:37
  • The issue is on desktops `click` event propagates on `label` but on mobiles it doesn't. Anyway, you shouldn't use `onclick` inline js, instead listen to `change` event on checkbox, radio button and selectmenu. – Omar Aug 03 '14 at 23:44

1 Answers1

1

OK, Have also been fiddling this.

Yes the click listener was only activated on the label and this is not reliably clicked on the mobile tap

I have changed the listener to listen to the check\change of the input (which always fires) and slightly modified the if to make it add on check and remove on uncheck.

 $(document).on('change', '#titlepage .ui-checkbox [type="checkbox"]', function () {
     var item = this;
     if (!item.checked) {
         var i = checkedItems.indexOf(item.id);
         if (i != -1) {
             checkedItems.splice(i, 1);
         }
     } else {
         checkedItems[checkedItems.length] = item.id;
     }
 });

Demo:http://jsfiddle.net/robschmuecker/vPj5D/11/ Mobile friendly fiddle http://jsfiddle.net/robschmuecker/vPj5D/11/show/light. This is tested and working on my android 2.3.4 stock browser.

Rob Schmuecker
  • 8,934
  • 2
  • 18
  • 34
  • That was it! Thanks much for the help. I also had another issue with using a pagebeforeshow event where I should have been using a panelbeforeopen event. Frustrating inconsistency. You would think onClick would be universal. – Adam6806 Aug 04 '14 at 00:24
  • 1
    Yes thing is, it actually is relatively universal but the way that you were appending the HTML dynamically you were attaching it just to the `label` which meant that it only sometimes registered. Perhaps we could have also attached it to the marked-up `li` elements but using the checkbox is the safest and most fool-proof as you needed to get the value of that for the comparisons in anycase. – Rob Schmuecker Aug 04 '14 at 00:36
  • 1
    Ah yes I see what you mean. Either way you are a gentleman and a scholar. Thanks again. – Adam6806 Aug 04 '14 at 01:20
  • My pleasure. Thanks for the kind words :-) ! – Rob Schmuecker Aug 04 '14 at 01:24