3
\$\begingroup\$

I'm doing a college assignment with jQuery Mobile and JSON. Best practice with jQuery mobile is my main concern.

My html starts off with a main 'page' (data-role="page") inside a div with id="all-pages".

I use jQuery's .getJSON method to connect to a local JSON file called profiles.json. profiles.json contains an array called profiles and has multiple objects. I loop through this in my jQuery and generate a list item (which is inserted to the main 'page') for each profile. I also generate a 'page' (ie data-role="page") for each profile and link to it in the list item.

Before I make the getJSON request, I created variables that store html such as the 'header', that will be used on every page in order to try not to repeat my code. I still have a lot of jQuery code to generate the html. I am wondering if I can make it more efficient? I.e. Is there a best practice when it comes to generating pages dynamically in jQuery Mobile?

HTML:

<div id="all-pages">
    <div data-role="page" id="page-home" data-theme="a">
        <!--this is the main 'page' in the app and it is static html. All other 'pages' will be generated dynamically-->
        <!--The number of pages that exist will depend on how many profiles exist in the profiles.json file-->
        <!--The number of profiles will also indicate how many list items will exist on the main page.-->

        <div data-role="header">
            <!--The home icon will be placed on the left side of the header on every page.-->
            <a id="home-button" href="#page-home" data-role="button" data-icon="home" data-iconpos="notext" data-inline="true">Home button</a>
            <h1>The Random Network</h1>

            <!--use the ui-btn-right class to position the bars icon to the right of the header.-->
            <a id="panel-button" href="#right-panel" class="ui-btn-right" data-role="button" data-icon="bars" data-iconpos="notext" >Panel button</a>
        </div>
        <div data-role="content">
            <div class="content-primary">
                <div data-demo-html="true">
                    <div>
                        <p>Welcome to the Random Network, where all kinds of random objects and things can socialize and meet new objects.</p>          
                    </div>
                    <!--use the data-filter-placeholder to customize the text in the filter input field. data-filter-reveal=true in order to only reveal the items after they match the input-->
                    <ul id="list-of-profiles" data-filter="true" data-filter-placeholder="Search objects..." data-inset="true" data-role="listview" data-filter-reveal="false">
                        <!--these list items will be created dynamically from the profiles.json file-->
                    </ul>
                </div>
            </div>
        </div>
        <div data-role="footer">
            <h1>Copyright Inanimate Objects</h1>
        </div>
    </div>

    <!--All other 'pages' will be generated dynamically and will be placed here-->
</div>

jQuery

$(document).ready(function(){
        var header = '<div data-role="header">' +
            '<a id="home-button" href="#page-home" data-role="button" data-icon="home" data-iconpos="notext" data-inline="true">Home button</a>' +
            '<a id="panel-button" href="#right-panel" class="ui-btn-right noshadow" data-role="button" data-icon="bars" data-iconpos="notext">Panel  button</a>' +
            '<h2>The Random Network</h2></div>';
        var content = '<div data-role="content">' +
                '<div class="content-primary"><!--this class content-primary is necessary for the panel--></div></div>';


        var intro_section = '<div class="intro">' +
                    '<img class="profile-photo large-image" width="250" heigh="250" />' +
                    '<h3 class="profile-name"></h3>' +
                    '<p class="intro-paragraph"></p></div><!--End Intro-->';
        var post_list = '<ul class="list-of-posts" data-filter="true" data-filter-placeholder="Search posts..." data-inset="true" data-role="listview" data-filter-reveal="false"></ul>';

        //this is necessary so that we can access our panel on all pages.
        $("body>[data-role='panel']").panel();  

        $.getJSON('profiles.json',{
                format: "json"
        }).done(function(data){
        var count = 0;
            $.each(data.profiles, function(i, profile){
            var id = profile.id;
            var first_name = profile.first_name;
            var last_name = profile.last_name;
            var intro = profile.intro_paragraph;
            var img_src = profile.profile_picture;
            console.log(first_name);
            var page_id = "page-" + profile.id;
            var list_id = "list-" + count;
            var anchor_id = "anchor-" + count;

            //generate a list item for each profile
            $("<li>").attr("id", list_id).attr("class", "list-item").appendTo("#list-of-profiles");
            $("<a>").attr("id", anchor_id).attr("data-transition", "pop").attr("href", "#" + page_id).appendTo("#" + list_id);
            $("<img>").attr("src", img_src).attr("class", "profile-thumbnail").attr("width", "50").attr("height", "50").appendTo("#" + anchor_id);
            $("<h3>" + first_name + "</h3>").appendTo("#" + anchor_id);
            $("<p>" + intro + "</p>").appendTo("#" + anchor_id);

            //generate pages for each profile
            $("<div>" + header + "</div>").attr("data-role", "page").attr("id", page_id).attr("data-theme", "a").appendTo("#all-pages");

            //$("#all-pages").append('<div data-role="page" id="' + page_id + '" data-theme="a">' + header + '</div>');
            $("#" + page_id).append(content);
            $("#" + page_id + " .content-primary").append(intro_section);
            $("#" + page_id + " .profile-photo").attr("src", img_src);
            $("#" + page_id + " .profile-name").html(first_name);
            $("#" + page_id + " .intro-paragraph").html(intro);
            $("#" + page_id + " .content-primary").append(post_list);

            console.log("intro" + intro);
            $.each(profile.posts, function(i, post){
                //go through the posts array and store information about each post into local variables.
                var post_id = "post-id-" + post.id;         //each post in the json file will have a unique 'id'
                var time = post.time;
                var date = post.date;
                var update_comment = post.update_comment;   
                var quantity_trophies = post.gifts.trophies;    //number of trophies is stored in the gifts array within the post object.
                var quantity_love = post.gifts.love;        //number of loves is stored in the gifts array within the post object.
                var quantity_thumbs_up = post.gifts.thumbs_up;  //number of thumbs_up is stored in the gifts array within the post object.
                var update_type = post.update_type; //this will be either 'status', 'photo' or 'video'

                console.log(update_type);

                //generate a list item for each post and give it an id of the post_id created above.
                $("<li>").attr("id", post_id).attr("class", "post").appendTo("#" + page_id + " .list-of-posts");
                $("<h4>" + first_name + "'s update</h4>").appendTo("#" + post_id);
                $("<p>" + time + " " + date + "</p>").attr("class", "post-date").appendTo("#" + post_id);
                $("<div>").attr("class", "update-area").appendTo("#" + post_id);
                $("<div>").attr("class", "update-comment").appendTo("#" + post_id + " .update-area");
                $("<span>").attr("class", "profile-thumbnail").appendTo("#" + post_id + " .update-comment");
                $("<img>").attr("src", img_src).attr("width", "50").attr("height", "50").appendTo("#" + post_id + " .profile-thumbnail");
                $("<p>").attr("class", "comment-name").appendTo("#" + post_id + " .update-comment");
                $("<a>" + first_name + "</a>").attr("data-transition", "pop").attr("href", "#" + page_id).appendTo("#" + post_id + " .comment-name");
                $("<p>" + update_comment +"</p>").appendTo("#" + post_id + " .update-comment");

                if(update_type == "photo"){
                    //if the update type is a photo then get the link of the photo from the json file
                    var update_photo = post.update_photo;

                    //add a div tag with a class of photo-area (for styling) and append it to the update-area
                    $("<div>").attr("class", "photo-area").appendTo("#" + post_id + " .update-area");

                    //create an image tag and use the update_photo link as the src of the image.
                    //append this img tag to the photo-area we created above.
                    $("<img>").attr("class", "large-image").attr("src", update_photo).appendTo("#" + post_id + " .photo-area");
                }

                if(update_type == "video"){
                    //get the video link from the current 'post' array.
                    var video_link = post.video_link; 

                    //firstly check if the video link contains the string "youtu.be/"
                    //That way we know if it's a youtube video and will therefore use an iframe tag
                    //and format the youtube string in the right way in order to embed the video
                    if(video_link.indexOf("youtu.be/") != -1){
                        //if the upate type is a video and it is a youtube link then we will need to add a div with a class of 
                        //'video-wrapper' in order to create a fluid width video.
                        //we will apend video-wrapper to the update-area div
                        $("<div>").attr("class", "video-wrapper").appendTo("#" + post_id + " .update-area");

                            //get the code at the end of the youtube string so that we can embed the video to an iframe.
                        var youtube_code = video_link.substr(video_link.lastIndexOf("/") + 1);

                        //Now we create a string which follows youtube's link format for embedding videos
                        //concatenate the youtube code we generated from the video link above, onto the embed string.
                        var youtube_embed_link = "https://www.youtube.com/embed/" + youtube_code;

                        //Create an iframe tag with the source equal to the embed string we created. 
                        //append the iframe to the div with class=video-wrapper
                        $("<iframe>").attr("src", youtube_embed_link).attr("width", "560").attr("height", "315").attr("frameborder", "0").appendTo("#" + post_id + " .video-wrapper");
                    }else if(video_link.indexOf(".mp4") != -1){

                        //if the video link is not a youtube link and contains .mp4 than use a 
                        //html5 video tag and use the video_link as the source.
                        //we will set the width of the video to 100% and the height to auto. 
                        $("<video>").attr("width", "100%").attr("height", "auto").attr("controls", true).appendTo("#" + post_id + " .update-area");
                        $("<source>").attr("src", video_link).attr("type", "video/mp4").appendTo("#" + post_id + " .update-area video");
                        $("<source>").attr("src", video_link).attr("type", "video/webm").appendTo("#" + post_id + " .update-area video");
                        //if the users browser does not support html5 video then we will display a message.
                        //We need to append the message to the video tag as a fallback
                        $(".update-area video").append("Your browser does not support HTML5 video");    
                    }
                }   


                //add in the gift area, where we show what "gifts" the user has received from other users for a particular 'post'
                $("<div>").attr("class", "gift-area").appendTo("#" + post_id);

                if(quantity_trophies != 0){
                    //if there are zero trophies in the json file for this post then do not display the trophy symbol
                    var trophy_title = "" + quantity_trophies + " trophies received"; //create a string for the title attribute
                    $('<span><i class="fa fa-trophy" aria-hidden="true"></i>(' + quantity_trophies + ')</span>').attr("class", "gift").attr("title", trophy_title).appendTo("#" + post_id + " .gift-area");

                }
                if(quantity_love != 0){
                    //if there are zero loves in the json file for this post then do not display the heart symbol
                    var love_title = "" + quantity_love + " loves received"; //create a string for the title attribute
                    $('<span><i class="fa fa-heart" aria-hidden="true"></i>(' + quantity_love + ')</span>').attr("class", "gift").attr("title", love_title).appendTo("#" + post_id + " .gift-area");
                    }
                if(quantity_thumbs_up != 0){
                    //if there are zero thumbs up in the json file for this post then do not display the thumbs up symbol
                    var thumbs_up_title = "" + quantity_thumbs_up + " thumbs up received"; //create a string for the title attribute
                    $('<span><i class="fa fa-thumbs-up" aria-hidden="true"></i>(' + quantity_thumbs_up + ')</span>').attr("class", "gift").attr("title", thumbs_up_title).appendTo("#" + post_id + " .gift-area");
                    }

                var comment_count = 0;  //set up a counter so we can create a unique class name for each user comment
                $.each(post.user_comments, function(i, comment){
                    //we go through this loop for each user comment
                    var comment_first_name = comment.first_name;        //this will be the name of the the user who commented
                    var comment_page_id = "page-" + comment.id;     //this will be the id of the profile page of the user who commented
                    var comment_picture = comment.profile_picture;  //this will be the profile picture of the the user who commented

                    //want to create unique class names for the different "comment-area"s and "comment-main"s so we can target them.
                    //every "comment-area" will have one "comment-main" div and possible "comment-reply" divs
                    //we will loop through the "comment-reply"s further down.

                    var unique_comment_area = "comment-area-" + comment_count; //create unique class name
                    var unique_comment_main = "comment-main-" + comment_count; //create unique class name

                    //create a div with a unique_comment_area class (in order to select this specific div) and also "comment-area" class (in order to apply css styling)
                    //and append this div to the current Post in the loop.
                    $("<div>").attr("class", unique_comment_area).addClass("comment-area").appendTo("#" + post_id);

                    $("<div>").attr("class", unique_comment_main).addClass("comment-main").appendTo("#" + post_id + " ." + unique_comment_area);
                    $("<span>").attr("class", "profile-thumbnail").appendTo("#" + post_id + " ." + unique_comment_area + " ." + unique_comment_main);
                    $("<img>").attr("src", comment_picture).attr("width", "50").attr("height", "50").appendTo("#" + post_id + " ." + unique_comment_area + " ." + unique_comment_main + " .profile-thumbnail");
                    $("<p>").attr("class", "comment-name").appendTo("#" + post_id + " ." + unique_comment_main);
                    $("<a>" + comment_first_name + "</a>").attr("data-transition", "pop").attr("href", "#" + comment_page_id).appendTo("#" + post_id + " ." + unique_comment_main + " .comment-name");
                    $("<p>" + comment.user_comment + "</p>").attr("class", "photo-comment").appendTo("#" + post_id + " ." + unique_comment_main);


                    var reply_count = 0; //set up a counter so we can create a unique class name for each reply
                    $.each(comment.replies, function(i, reply){
                        var reply_first_name = reply.first_name;    //this will be the name of the the user who replied to the first comment
                        var reply_page_id = "page-" + reply.id;     //this will be the id of the profile page of the user who replied
                        var reply_picture = reply.profile_picture;  //this will be the profile picture of the the user who replied      
                        var unique_reply_class = "comment-reply-" + reply_count; //create unique class name

                        $("<div>").attr("class", unique_reply_class).addClass("comment-reply").appendTo("#" + post_id + " ." + unique_comment_area);
                        $("<span>").attr("class", "profile-thumbnail").appendTo("#" + post_id + " ." + unique_comment_area + " ." + unique_reply_class);
                        $("<img>").attr("src", reply_picture).attr("width", "50").attr("height", "50").appendTo("#" + post_id + " ." + unique_comment_area + " ." + unique_reply_class + " .profile-thumbnail");
                        $("<p>").attr("class", "comment-name").appendTo("#" + post_id + " ." + unique_comment_area + " ." + unique_reply_class);
                        $("<a>" + reply_first_name + "</a>").attr("data-transition", "pop").attr("href", "#" + reply_page_id).appendTo("#" + post_id + " ." + unique_comment_area + " ." + unique_reply_class + " .comment-name");
                        $("<p>" + reply.user_comment + "</p>").attr("class", "photo-comment").appendTo("#" + post_id + " ." + unique_comment_area + " ." + unique_reply_class);

                        reply_count++;
                    }); 
                    comment_count++;    
                });
            });
        count++;        
            });

        $('#list-of-profiles').listview('refresh'); 
        });

    });

JSON:

{"profiles":[   {"id":"0001",
        "first_name":"Vicki",
        "last_name":"Phillips",
        "profile_picture":"images/img-0001-1.jpg",
        "intro_paragraph":"hi ya'll. I'm the token human on this site.",
        "posts":[{"id":"0001-0001",
            "date":"22-04-2016",
            "time":"19:01",
            "update_type":"status",
            "update_comment":"Had an amazing time at the beach today.",
            "user_comments":[{"id":"0003",
                    "first_name":"Mr Bush",
                    "last_name":"",
                    "profile_picture":"images/img-0003-1.jpg", 
                    "user_comment":"lucky you",
                    "replies":[{"id":"0001",
                        "first_name":"Vicki",
                        "last_name":"Phillips",
                        "profile_picture":"images/img-0001-1.jpg", 
                        "user_comment":"Thanks"},
                        {"id":"0002",
                        "first_name":"Pie",
                        "last_name":"",
                        "profile_picture":"images/img-0002-1.jpg", 
                        "user_comment":"Your Welcome"}]
                    },
                    {"id":"0002",
                    "first_name":"Pie",
                    "last_name":"",
                    "profile_picture":"images/img-0002-1.jpg", 
                    "user_comment":"oh",
                    "replies":[{"id":"0001",
                        "first_name":"Vicki",
                        "last_name":"Phillips",
                        "profile_picture":"images/img-0001-1.jpg", 
                        "user_comment":"Thanks"},
                        {"id":"0002",
                        "first_name":"Pie",
                        "last_name":"",
                        "profile_picture":"images/img-0002-1.jpg", 
                        "user_comment":"Your Welcome"}]
                    }],
            "gifts":{"trophies":"0","love":"4","thumbs_up":"3"}},
            {"id":"0001-0002",
            "date":"14-04-2016",
            "time":"17:01",
            "update_type":"status",
            "update_comment":"Totes excited today.",
            "user_comments":[],
            "gifts":{"trophies":"13","love":"4","thumbs_up":"3"}},
            {"id":"0001-0003",
            "date":"02-04-2016",
            "time":"18:01",
            "update_type":"photo",
            "update_comment":"Got a new job working for VirtualRealty. Yippeeee!",
            "update_photo":"images/img-0002-2.jpg",
            "user_comments":[{"id":"0002",
                    "first_name":"Pie",
                    "last_name":"",
                    "profile_picture":"images/img-0002-1.jpg", 
                    "user_comment":"Well done!! Trophy for you",
                    "replies":[{"id":"0001",
                        "first_name":"Vicki",
                        "last_name":"Phillips",
                        "profile_picture":"images/img-0001-1.jpg", 
                        "user_comment":"Thanks. I'm very happy"},
                        {"id":"0002",
                        "first_name":"Pie",
                        "last_name":"",
                        "profile_picture":"images/img-0002-1.jpg", 
                        "user_comment":"Your Welcome"}]
                    }],
            "gifts":{"trophies":"20","love":"11","thumbs_up":"6"}},
            {"id":"0001-0004",
            "date":"05-03-2016",
            "time":"15:01",
            "update_type":"video",
            "update_comment":"One of my all time favorite songs!",
            "video_link":"https://youtu.be/9ro0FW9Qt-4",
            "user_comments":[{"id":"0003",
                    "first_name":"Mr Bush",
                    "last_name":"",
                    "profile_picture":"images/img-0003-1.jpg", 
                    "user_comment":"Wow! Brings me back",
                    "replies":[]
                    }],
            "gifts":{"trophies":"0","love":"12","thumbs_up":"3"}},
            {"id":"0001-0005",
            "date":"05-03-2016",
            "time":"15:01",
            "update_type":"video",
            "update_comment":"Came across this lil video today. love it!",
            "video_link":"videos/mov_bbb.mp4",
            "user_comments":[{"id":"0003",
                    "first_name":"Mr Bush",
                    "last_name":"",
                    "profile_picture":"images/img-0003-1.jpg", 
                    "user_comment":"Aw cute!!",
                    "replies":[]
                    }],
            "gifts":{"trophies":"0","love":"5","thumbs_up":"1"}}]
        },
        {"id":"0002",
        "first_name":"Pie",
        "last_name":"",
        "profile_picture":"images/img-0002-1.jpg",
        "intro_paragraph":"pieeee.",
        "posts":[{"id":"0002-0001",
            "date":"24-01-2014",
            "time":"19:01",
            "update_type":"status",
            "update_comment":"pieeeee.",
            "user_comments":[],
            "gifts":{"trophies":"13","love":"4","thumbs_up":"3"}},
            {"id":"0002-0002",
            "date":"24-01-2014",
            "time":"19:01",
            "update_type":"status",
            "update_comment":"pieeeeeeeeeeeeeeeee.",
            "user_comments":[],
            "gifts":{"trophies":"13","love":"4","thumbs_up":"3"}}]
        }]
}
\$\endgroup\$
  • \$\begingroup\$ Welcome to Code Review! I hope you get some good answers. \$\endgroup\$ – Phrancis May 9 '16 at 22:27
2
\$\begingroup\$

I suggest using a JS template engine like http://handlebarsjs.com/ if this is appropriate for your project. In your HTML file you can define several templates wrapped in a tag:

<script id="entry-template" type="text/x-handlebars-template">
  <div class="entry">
    <h1>{{title}}</h1>
    <div class="body">
      {{body}}
    </div>
  </div>
</script>

in you JS you define all the {{vars}}, optional compile the template (performance, especially for mobile), then let jQ append it:

var context = {title: "My New Post", body: "This is my first post!"};
var html    = template(context);
$('#myDiv').append(html);

But once you do, the template vars are fix you cannot change them. You cannot nest these templates. handlebarsjs is not the only, but the most common template engine

\$\endgroup\$
  • \$\begingroup\$ This looks good however for this project we are not required to use a template engine. I was mainly wondering If I have used any bad practices in my jQuery code when generating the html code dynamically? thanks for your help :) \$\endgroup\$ – Sarah May 10 '16 at 1:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.