With the recent “alpha 1” release of JQuery Mobile. I decided to learn about this new framework and create a simple mobile blog. With this new framework we can target several platforms easily:
- Apple iOS: iPhone, iPod Touch, iPad (all versions)
- Android: all devices (all versions)
- Blackberry Torch (version 6)
- Palm WebOS Pre, Pixi
- Nokia N900
Let’s start…
Update – Nov. 11, 2010: Code updated to reflect changes in JQuery Mobile Alpha 2.
Update – April 5, 2011: Code updated to reflect changes in JQuery Mobile Alpha 4. Fixed capitalization in code for “posts” table.
I built this using PHP, Apache 2, and of course JQuery Mobile. To keep it simple I’m only using two PHP files, the bulk of the code is in a file called index.php. The code to insert new posts is in a file called newpost.php. Please keep in mind this code was put together quickly as a demo more than anything so if you use this as a base for a future projects you need to validate the data, ensure strings lengths are of acceptable ranges, and much more, etc.
The nice thing about working with JQuery Mobile is that I was able to use Google Chrome to easily debug and view my work as I proceeded. I found IE 7 though to be problematic. I didn’t test any other browsers.
The MySQL script for the database is very straight forward:
CREATE
DATABASE
MobileBlog;
CREATE
TABLE
IF
NOT
EXISTS `posts` (
`post_id`
int
(10) unsigned
NOT
NULL
AUTO_INCREMENT,
`post_title`
varchar
(100)
NOT
NULL
,
`post_content` text
NOT
NULL
,
`post_date`
timestamp
NOT
NULL
DEFAULT
CURRENT_TIMESTAMP
,
PRIMARY
KEY
(`post_id`)
) ENGINE=MyISAM
Simply a place to put the blog post’s title, content and the time it was created.
With the database in place let’s move onto the HTML and JQuery code.
The header is simple enough with a call to grab the JQuery files we will need:
<!DOCTYPE html>
<
html
>
<
head
>
<
title
>MobileBlog</
title
>
<
link
rel
=
"stylesheet"
href
=
"http://code.jquery.com/mobile/1.0a4/jquery.mobile-1.0a4.min.css"
/>
<
script
src
=
"http://code.jquery.com/jquery-1.5.2.min.js"
></
script
>
<
script
src
=
"http://code.jquery.com/mobile/1.0a4/jquery.mobile-1.0a4.min.js"
></
script
>
</
head
>
The nice thing is you now have all the power of JQuery available to you in the mobile framework.
Laying out the initial view is very straight forward and you can read more about it as well as grab a starter template here.
<
div
data-role
=
"page"
id
=
"indexPage"
>
<
div
data-role
=
"header"
>
<
h1
>Welcome!</
h1
>
</
div
>
<
div
data-role
=
"content"
>
<
ul
data-role
=
"listview"
>
<
li
>
<
a
href
=
"#createNewPostPage"
>Create New Post</
a
>
</
li
>
<
li
>
<
a
href
=
"#readBlogPage"
>Read Blog</
a
>
</
li
>
<
li
>
<
a
href
=
"#aboutMobileBlogPage"
>About MobileBlog</
a
>
</
li
>
</
ul
>
</
div
>
<
div
data-role
=
"footer"
>
<
h1
>- MobileBlog -</
h1
>
</
div
>
</
div
>
Typical structure once the container is in place looks like this:
<
div
data-role
=
"header"
>...</
div
>
<
div
data-role
=
"content"
>...</
div
>
<
div
data-role
=
"footer"
>...</
div
>
The first component I used was a List View and you need to get familiar with these since they are going to be a primary component when working with this mobile framework.
I then laid out a few more pages. One to create new posts, one to read them, and an about page. In the case of creating a new post I used Ajax to call the newpost.php file which looks like this:
<?php
try
{
$connection
= mysql_connect(
"localhost"
,
"mobileblog"
,
"password"
);
mysql_select_db(
"MobileBlog"
,
$connection
);
// Note: You need to verify the data coming in isn't harmful, this SQL pretty much puts anything into the database so make sure to change this!
$postTitle
= mysql_real_escape_string(
$_POST
[postTitle]);
$postContent
= mysql_real_escape_string(
$_POST
[postContent]);
mysql_query(
"INSERT INTO posts (post_title, post_content) VALUES ('$postTitle', '$postContent')"
);
mysql_close(
$connection
);
echo
"SUCCESS"
;
}
catch
(Exception
$e
)
{
echo
$e
->getMessage();
// Note: Log the error or something
}
?>
Very simple code and directly to the point. If the insert works a string is passed back as “SUCCESS” otherwise the error is passed back. Obviously in a production environment you would want to hide the true error from the user and dump a more friendly message to them.
The Ajax code looks like this to make the save:
$(document).ready(
function
() {
$(
"#submit"
).click(
function
(){
var
formData = $(
"#newPostForm"
).serialize();
$.ajax({
type:
"POST"
,
url:
"/mobile/newpost.php"
,
cache:
false
,
data: formData,
success: onSuccess
});
return
false
;
});
$(
"#cancel"
).click(
function
(){
resetTextFields();
});
$(
"#refresh"
).click(
function
(){
location.reload();
});
});
On a successful Ajax call this code is called:
function
onSuccess(data, status)
{
resetTextFields();
// Notify the user the new post was saved
$(
"#notification"
).fadeIn(2000);
data = $.trim(data);
if
(data ==
"SUCCESS"
)
{
$(
"#notification"
).css(
"background-color"
,
"#ffff00"
);
$(
"#notification"
).text(
"The post was saved"
);
}
else
{
$(
"#notification"
).css(
"background-color"
,
"#ff0000"
);
$(
"#notification"
).text(data);
}
$(
"#notification"
).fadeOut(5000);
}
To read the blogs posts I simply put the PHP code directly in rather than make an Ajax call and populate it as needed. I also added a refresh button since any new posts added after the site loads won’t show up automatically. Ideally you would want to load the post titles into a List View and then link to the full article and load just that data since loading everything at once could get very slow if you are loading a lot of posts with content. In fact on a mobile device you could easily frustrate the user so keep this in mind. Its really about speed with mobile web apps.
The code looks like this to read the blog posts:
<div data-role=
"page"
id=
"readBlogPage"
>
<div data-role=
"header"
>
<h1>Read Blog</h1>
</div>
<div data-role=
"content"
>
<button data-theme=
"b"
data-role=
"button"
data-iconpos=
"left"
id=
"refresh"
type=
"button"
data-icon=
"refresh"
>Refresh</button>
<ul data-role=
"listview"
data-theme=
"d"
data-inset=
"true"
>
<!-- Note: You should really display the blog post articles
and
then link to the full article, since this is a simple demo
I'm just loading all the articles, obviously this is not a production quality blog since this could take a long
time to load all the articles
and
on a mobile device speed counts. Also, this data won't automatically refresh on a
new
post insert.
-->
<?php
try
{
$connection
= mysql_connect(
"localhost"
,
"mobileblog"
,
"password"
);
mysql_select_db(
"MobileBlog"
,
$connection
);
$result
= mysql_query(
"SELECT * FROM posts"
);
while
(
$row
= mysql_fetch_array(
$result
))
{
echo
"<li><h2>"
.
$row
[
'post_title'
] .
"</h2>"
.
$row
[
'post_content'
] .
"<p class='ui-li-aside'>"
.
$row
[
'post_date'
] .
"<strong></p>"
;
}
mysql_close(
$connection
);
}
catch
(Exception
$e
)
{
echo
$e
->getMessage();
}
?>
</ul>
</div>
<div data-role=
"footer"
>
<h1>- MobileBlog -</h1>
</div>
</div>
The final code looks like this:
<!DOCTYPE html>
<html>
<head>
<title>MobileBlog</title>
<link rel=
"stylesheet"
href=
"http://code.jquery.com/mobile/1.0a4/jquery.mobile-1.0a4.min.css"
/>
<script src=
"http://code.jquery.com/jquery-1.5.2.min.js"
></script>
<script src=
"http://code.jquery.com/mobile/1.0a4/jquery.mobile-1.0a4.min.js"
></script>
</head>
<body>
<script type=
"text/javascript"
>
function
resetTextFields()
{
$(
"#postTitle"
).val(
""
);
$(
"#postContent"
).val(
""
);
}
function
onSuccess(data, status)
{
resetTextFields();
// Notify the user the new post was saved
$(
"#notification"
).fadeIn(2000);
data = $.trim(data);
if
(data ==
"SUCCESS"
)
{
$(
"#notification"
).css(
"background-color"
,
"#ffff00"
);
$(
"#notification"
).text(
"The post was saved"
);
}
else
{
$(
"#notification"
).css(
"background-color"
,
"#ff0000"
);
$(
"#notification"
).text(data);
}
$(
"#notification"
).fadeOut(5000);
}
$(document).ready(
function
() {
$(
"#submit"
).click(
function
(){
var
formData = $(
"#newPostForm"
).serialize();
$.ajax({
type:
"POST"
,
url:
"/mobile/newpost.php"
,
cache: false,
data: formData,
success: onSuccess
});
return
false;
});
$(
"#cancel"
).click(
function
(){
resetTextFields();
});
$(
"#refresh"
).click(
function
(){
location.reload();
});
});
</script>
<!-- indexPage -->
<div data-role=
"page"
id=
"indexPage"
>
<div data-role=
"header"
>
<h1>Welcome!</h1>
</div>
<div data-role=
"content"
>
<ul data-role=
"listview"
>
<li>
<a href=
"#createNewPostPage"
>Create New Post</a>
</li>
<li>
<a href=
"#readBlogPage"
>Read Blog</a>
</li>
<li>
<a href=
"#aboutMobileBlogPage"
>About MobileBlog</a>
</li>
</ul>
</div>
<div data-role=
"footer"
>
<h1>- MobileBlog -</h1>
</div>
</div>
<!-- createNewPostPage -->
<div data-role=
"page"
id=
"createNewPostPage"
>
<div data-role=
"header"
>
<h1>Create New Post</h1>
</div>
<div data-role=
"content"
>
<div data-role=
"content"
>
<form id=
"newPostForm"
>
<div data-role=
"fieldcontain"
>
<label
for
=
"postTitle"
><strong>Post Title:</strong></label>
<input type=
"text"
name=
"postTitle"
id=
"postTitle"
value=
""
/>
<label
for
=
"postContent"
><strong>Post Content:</strong></label>
<textarea name=
"postContent"
id=
"postContent"
></textarea>
<fieldset
class
=
"ui-grid-a"
>
<div
class
=
"ui-block-a"
><a href=
"#indexPage"
id=
"cancel"
data-role=
"button"
>Cancel</a></div>
<div
class
=
"ui-block-b"
><button data-theme=
"b"
id=
"submit"
type=
"submit"
>Submit</button></div>
</fieldset>
<h3 id=
"notification"
></h3>
</div>
</form>
</div>
</div>
<div data-role=
"footer"
>
<h1>- MobileBlog -</h1>
</div>
</div>
<!-- readBlogPage -->
<div data-role=
"page"
id=
"readBlogPage"
>
<div data-role=
"header"
>
<h1>Read Blog</h1>
</div>
<div data-role=
"content"
>
<button data-theme=
"b"
data-role=
"button"
data-iconpos=
"left"
id=
"refresh"
type=
"button"
data-icon=
"refresh"
>Refresh</button>
<ul data-role=
"listview"
data-theme=
"d"
data-inset=
"true"
>
<!-- Note: You should really display the blog post articles
and
then link to the full article, since this is a simple demo
I'm just loading all the articles, obviously this is not a production quality blog since this could take a long
time to load all the articles
and
on a mobile device speed counts. Also, this data won't automatically refresh on a
new
post insert.
-->
<?php
try
{
$connection
= mysql_connect(
"localhost"
,
"mobileblog"
,
"password"
);
mysql_select_db(
"MobileBlog"
,
$connection
);
$result
= mysql_query(
"SELECT * FROM posts"
);
while
(
$row
= mysql_fetch_array(
$result
))
{
echo
"<li><h2>"
.
$row
[
'post_title'
] .
"</h2>"
.
$row
[
'post_content'
] .
"<p class='ui-li-aside'>"
.
$row
[
'post_date'
] .
"<strong></p>"
;
}
mysql_close(
$connection
);
}
catch
(Exception
$e
)
{
echo
$e
->getMessage();
}
?>
</ul>
</div>
<div data-role=
"footer"
>
<h1>- MobileBlog -</h1>
</div>
</div>
<!-- aboutMobileBlogPage -->
<div data-role=
"page"
id=
"aboutMobileBlogPage"
>
<div data-role=
"header"
>
<h1>About MobileBlog</h1>
</div>
<div data-role=
"content"
>
<div data-role=
"content"
>
<div data-role=
"fieldcontain"
>
<p><a href=
"http://giantflyingsaucer.com/blog/?p=1856"
>MobileBlog</a></p>
<p>Created by: <a href=
"http://twitter.com/chadlung"
>Chad Lung</a></p>
<p>Powered by: <a href=
"http://jquerymobile.com"
>JQuery Mobile</a></p>
</div>
</div>
</div>
<div data-role=
"footer"
>
<h1>- MobileBlog -</h1>
</div>
</div>
</body>
</html>
I then used the Android Emulator to view MobileBlog running using this address: http://10.0.2.2/mobile – Keep in mind you cannot use “localhost” in the emulator.
Here are some screenshots of MobileBlog running: