Advanced jQuery Mobile tutorial – Part 3 – Dynamic Content

Written by on April 8, 2015

Advanced jQuery Mobile tutorial – Part 3 – Dynamic Content

HTML:
<!DOCTYPE html>
<html>
    <head>
        <title>jQM Complex Demo</title>
        <meta name="viewport" content="initial-scale=1, maximum-scale=1"/>
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.min.css" /> 
        <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script>
        <script src="http://code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.min.js"></script>    
    </head>
    <body>
        <div data-role="page" id="index">
            <div data-theme="b" data-role="header">
                <h3>
                    City Search
                </h3>
            </div>        
            <div data-role="content">
                <div class="example-wrapper" data-iscroll>
                    <input name="city-search" id="city-search" value="London" type="text" placeholder="Enter City Name"/>            
                    <a href="#" class="ui-btn" id="city-search-btn">Search</a>
                </div>
            </div>            
        </div> 
    </body>
</html>   
JavaScript
$(document).on('pageinit', '#index', function(){        
    $(document).on('click', '#city-search-btn', function(){ 
        var cityName = $('#city-search').val();
        if(cityName.length > 0) {
            var url = 'http://api.openweathermap.org/data/2.5/weather?q='+cityName+'&amp;units=metric';    
            $.ajax({
                url: url,
                dataType: "jsonp",
                async: true,
                beforeSend: function() {
                    // This callback function will trigger before data is sent
                    $.mobile.loading('show', {theme:"a", text:"Please wait...", textonly:false, textVisible: true}); // This will show ajax spinner
                },
                complete: function() {
                    // This callback function will trigger on data sent/received complete
                    $.mobile.loading('hide'); // This will hide ajax spinner
                },                
                success: function (result) {
                    ajax.parseJSONP(result);
                },
                error: function (request,error) {
                    alert('Network error has occurred please try again!');
                }
            });          
        } else {
            alert('Please enter city name!');
        }       
    });        
});

$(document).on('pagehide', '#map', function(){   
    $(this).remove();
});

$(document).on('pageshow', '#map',function(e,data){   
    var minZoomLevel = 12;
    
    var myLatLng = new google.maps.LatLng(weatherData.response.coord.lat, weatherData.response.coord.lon);
    
    var map = new google.maps.Map(document.getElementById('map_canvas'), {
        zoom: minZoomLevel,
        center: myLatLng,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    });
    
    var image = {
        url: 'http://openweathermap.org/img/w/'+weatherData.response.weather[0].icon+'.png'
    };
    
    infoWindow = new google.maps.InfoWindow();
    infoWindow.setOptions({
        content: "<div class='info-window'><div class='icon-holder'><img src='http://openweathermap.org/img/w/"+weatherData.response.weather[0].icon+".png'/></div><div class='info-holder'><span class='info-text'>City:</span><br/>"+weatherData.response.name+"<br/><span class='info-text'>Min. Temp:</span><br/>"+weatherData.response.main.temp_min+" °C<br/><span class='info-text'>Temp:</span><br/>"+weatherData.response.main.temp+" °C<br/><span class='info-text'>Max. Temp:</span><br/>"+weatherData.response.main.temp_max+" °C</div></div>",
        position: myLatLng,
    });
    infoWindow.open(map);     
    
});

var ajax = {  
    parseJSONP:function(result){  
        weatherData.response = result;
        //alert(JSON.stringify(weatherData.response.weather[0].icon));
        var mapPage    =   $('<div>').attr({'id':'map','data-role':'page'}).appendTo('body');
        var mapHeader  = $('<div>').attr({'data-role':'header', 'data-theme' : 'b','id':'map-header'}).appendTo(mapPage);
        $('<h3>').html(weatherData.response.name + ' weather').appendTo(mapHeader);
        $('<a>').attr({'href':'#index', 'class' : 'ui-btn-righ'}).html('Back').appendTo(mapHeader);
        var mapContent = $('<div>').attr({'data-role':'content'}).appendTo(mapPage);
        $('<div>').attr({'id':'map_canvas', 'style':'height:100%'}).appendTo(mapContent);
        $.mobile.changePage( "#map", { transition: "slide"});
    }
}

var weatherData = {
    response : null
}
CSS
.ui-content {
    padding: 0 !important;
    margin: 0 !important;
    position : absolute !important;
    top : 42px !important; 
    right : 0;
    bottom : 0 !important; 
    left : 0 !important; 
}

.info-window {
    width: 180px;
    height: 180px;
}
 
.icon-holder, info-holder {
    float: left;
    width: 50%;
    height: 100%;
}

.info-text {
    font-weight: bold;
}

Example 2

But what if we want to add dynamic content to already existing page, what to do in that case? This is an excellent question and usually something new jQuery Mobile developers don’t understand properly. When working with pre-existing page it is not enough to just add new dynamic content, we also need to enhance new content markup. In our previous example we were working with a fully dynamically created page so this process was unnecessary.

Lets look at this code snippet (I will show you full example at the end):

$(document).on('pagebeforeshow', '#index', function(){    
    // Add a new select element
    $('[data-role="content"]').append('<select name="select-choice-1" id="select-choice-1"><option value="standard">Standard: 7 day</option><option value="rush">Rush: 3 days</option></select>');
    .
    .
    .
    $('[data-role="content"]').trigger('create');
});

As you can see we are appending new content to previously empty page content div, but you should carefully look at the last line:

$(document).on('pagebeforeshow', '#index', function(){    
    .
    .
    .
    $('[data-role="content"]').trigger('create');
});

Method trigger() is used enhance markup of dynamically created content. This method can accept two different parameters, one is create and second one is pagecreate. First one is used only if we want to enhance content div container, second one is used if we want to enhance whole page, including header and footer.

But this is not everything, every jQuery Mobile widget has an unique enhancement method. If you want to learn how to work with specific dynamic widgets take a look at this article. There you’ll be able to find a working example for every jQuery Mobile widget plus some other necessary information regarding this topic.

Let me show you a working jsFiddle example, find it here: http://jsfiddle.net/Gajotres/426NU/ or play with it directly:

HTML:
<!DOCTYPE html>
<html>
<head>
    <title>jQM Complex Demo</title>
    <meta name="viewport" content="width=device-width"/>
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.min.css" /> 
        <script src="http://code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.min.js"></script>   
</head>
<body>
    <div data-role="page" id="index">
        <div data-theme="a" data-role="header">
            <h3>
                First Page
            </h3>
            <a href="#second" class="ui-btn-right">Next</a>
        </div>

        <div data-role="content">

        </div>


        <div data-theme="a" data-role="footer" data-position="fixed">
        
        </div>
    </div>   
</body>
</html>    
JavaScript:
$(document).on('pagebeforeshow', '#index', function(){    
    // Add a new select element
    $('[data-role="content"]').append('<select name="select-choice-1" id="select-choice-1"><option value="standard">Standard: 7 day</option><option value="rush">Rush: 3 days</option></select>');
    $('[data-role="content"]').append('<input type="range" name="slider-1" id="slider-1" value="60" min="0" max="100" />');
    $('[data-role="content"]').append('<input type="search" name="search" id="search-basic" value="" />');
    $('[data-role="content"]').append('<input type="button" value="Press me"/>');    
    // Enhance new select element
    $('[data-role="content"]').trigger('create');
});

Who Am I?

Between working as a senior Java developer in one of the largest insurance companies in the world and traveling, in my free time, I work as a professional mobile development adviser. I'm also a major jQuery Mobile supporter back at StackOverflow and a forum moderator at the official Ionic Framework forum.



Categories

8 thoughts on “Advanced jQuery Mobile tutorial – Part 3 – Dynamic Content”

  1. Hi Dragan

    very nice article thank you. It gave me some clues about dynamically building mobile web pages, particularly collapsibles and also my header will be dynamic.

    One of your links are broken here: “If you want to learn how to work with specific dynamic widgets take a look at this article. ”

    Best, Tony

  2. How do you implement using your same code to pull and display the weather data of multiple cities. What I mean with clicking anything you wan to pull data of multiple cities and display.

    Thank it is an excellent tutorial

    Abdi

  3. Dragan,

    It all makes sense, I thank you very much. You are good coach for coding. I like you how you keep things simple.Happy new year my friend.

    Put some Java/Android tutorial given that you have experience in that. I am craving for that ?

    Kind Regards,

    Abdi

  4. I’m working on a jQuery mobile website. Would you recommend to combine it with backbone.js/require.js/ember.js to get a MVC structure? Do you have any articles about it?

  5. Can not say more thank YOU to you !

    One question, what if the app has a login page, should it be inclued as a page in the first html ?
    Or I just need to put all the essential pages into the second html after login page ?

    Thank you !

Leave a Reply