Jun 24, 2018

jQuery: Creating Milkshake application - step by step tutorial




What We’re Going To Build
In this article I am going to describe steps to develop a simple javascript application which allows user to mix drinks with milk and prepare milk shake.
These steps aim to cover the entire source code of the application. However, before diving in, I need to clarify a few libraries I have used to develop the application.

jQuery
jQuery is small, cross browser, feature-rich javascript library which easily allows developer to select HTML elements, traversal, AJAX & DOM manipulation. You can learn more about jQuery by following below link:

Bootstrap
Bootstrap is a free and open-source front-end library for designing responsive websites and web applications. https://getbootstrap.com/docs/4.1/getting-started/introduction/ 

UnderscoreJs
Underscorejs is javascript library for querying and filtering in-memory json data

Step 1. Design

This is a simple drink maker application and as you can see the user interface is split up into four sections.
1. Select drink
2. Select flavor
3. Payment
4. Make Drink

We are using following JSON as our data store, in real world scenario this json will be retrieved from server.

    this.data = [{
        categoryid: 1,
        name: 'Milk Shake',
        description: '',
        image: 'images/drinks/milkshake.png',
        items: [
            { id: 1, name: 'Cherry', image: 'images/drinks/fruits/cherry.png', price: 11 },
            { id: 2, name: 'Grape', image: 'images/drinks/fruits/grape.png', price: 12 },
            { id: 3, name: 'Lemon', image: 'images/drinks/fruits/lemon.png', price: 10 },
            { id: 4, name: 'Lime', image: 'images/drinks/fruits/lime.png', price: 13 },
            { id: 5, name: 'Orange', image: 'images/drinks/fruits/orange.png', price: 10 },
            { id: 6, name: 'Peach', image: 'images/drinks/fruits/peach.png', price: 14 },
            { id: 7, name: 'Raspberry', image: 'images/drinks/fruits/raspberry.png', price: 21 },
            { id: 8, name: 'Strawberry', image: 'images/drinks/fruits/strawberry.png', price: 14 },
            { id: 9, name: 'Vanilla', image: 'images/drinks/fruits/vanilla.png', price: 10 }
        ]
    }, {
        categoryid: 2,
        name: 'Cold Drink',
        description: '',
        image: 'images/drinks/colddrink.jpg',
        items: [
            { id: 10, name: 'Coca-Cola', image: 'images/drinks/cola/cocacola.png', price: 12 },
            { id: 11, name: 'Dr Pepper', image: 'images/drinks/cola/drpepper.png', price: 14 },
            { id: 12, name: 'Fanta', image: 'images/drinks/cola/fanta.png', price: 15 },
            { id: 13, name: 'Mello Yello', image: 'images/drinks/cola/melloyello.png', price: 10 },
            { id: 14, name: 'Minute Maid', image: 'images/drinks/cola/minutemaid.png', price: 11 },
            { id: 15, name: 'Sprite', image: 'images/drinks/cola/sprite.png', price: 13 }
        ]
}];

Above json declares two categories(Milk Shake & Cold Drink) and items within each of the category.

Building UI & attaching events to the DOM elements

Create new project in your favorite code editor, for this tutorial I am using visual studio. You can use notepad too.

In the project create new html file “index.html” and add reference to jQuery and twitter bootstrap.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>JavaScript drink maker v1.0</title>
    <link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
    <link href="styles.css" rel="stylesheet" />
    <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
    <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.0/underscore-min.js"></script></head>
<body>

    <script src="scripts.js"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            alert("test");
        });
    </script>
</body>
</html>

The $( document ).ready() will only run once the page Document Object Model (DOM) is ready for JavaScript code to execute after the HTML loads in the browser.

To build above UI we will use the bootstap nav tabs component. Here’s link for your reference: https://getbootstrap.com/docs/4.0/components/navs/#tabs
Each nav is associated with tab content which is specified using “a” tag having “href” attribute, the data-toggle attribute of that “a” tag specifies that it toggles the tab contents.

<div class="board">
                    <!-- <h2>Welcome to IGHALO!<sup>™</sup></h2>-->
                    <div class="board-inner">
                        <ul class="nav nav-tabs" id="myTab">
                            <div class="liner"></div>
                            <li class="active">
                                <a id="liHome" href="#home" data-toggle="tab" title="Home">
                                    <span class="round-tabs one">
                                        <i class="glyphicon glyphicon-home"></i>
                                    </span>
                                </a></li>

                            <li><a class="disabled" id="liSelectDrink" href="#SelectDrink" onclick="return false;" data-toggle="tab" title="Select Drink">
                                <span class="round-tabs two">
                                    <i class="glyphicon glyphicon-glass"></i>
                                </span>
                            </a>
                            </li>
                            <li><a id="liSelectFlavor" href="#SelectFlavor" onclick="return false;" data-toggle="tab" title="Select Flavour">
                                <span class="round-tabs three">
                                    <i class="glyphicon glyphicon-glass"></i>
                                </span></a>
                            </li>

                            <li><a id="liPayment" href="#Payment" onclick="return false;" data-toggle="tab" title="Payment">
                                <span class="round-tabs four">
                                    <i class="glyphicon glyphicon-bookmark"></i>
                                </span>
                            </a></li>

                            <li><a id="liMakeDrink" href="#MakeDrink" onclick="return false;" data-toggle="tab" title="Make Drink">
                                <span class="round-tabs five">
                                    <i class="glyphicon glyphicon-ok"></i>
                                </span></a>
                            </li>

                        </ul>
                    </div>

                    <div class="tab-content">
                        <div class="tab-pane fade in active" id="home">

                        </div>
                        <div class="tab-pane fade" id="SelectDrink" style="padding-top:0px">
                           
                        </div>
                        <div class="tab-pane fade" id="SelectFlavor" style="padding-top:0px">
                           
                        </div>
                        <div class="tab-pane fade" id="Payment">
                           
                        </div>
                        <div class="tab-pane fade" id="MakeDrink">
                           
                        </div>
                        <div class="clearfix"></div>
                    </div>

                </div>

To switch to the next tab we will call the tab’s show function as follows

<a id="startMaking" href="javascript:void(0)" class="btn btn-success btn-outline-rounded green">Start Making Drink</a>

$("#startMaking").click(function () {
        $("#liSelectDrink").tab("show");
});

MakeDrink Prototype
All JavaScript objects inherit properties and methods from a prototype.
We add properties and methods to the MakeDrink function prototype by using `MakeDrink.prototype = {}` this code.
The `GetCategories` function is used for retrieving only categories list,
The `GetItems` function is used for retrieving drink item details from particular category.
The `InitializeUI` functions loads/binds data into the HTML DOM elements using jQuery.
`ShowDrinks` functions loads drinks list in the UI.

function MakeDrink() {
    this.SelectedCategory = 1;
    this.SelectedItem = 1;

    this.Name = "";
    this.Price = 0;

    this.data = [];
}

MakeDrink.prototype = {
    GetCategories: function () {
        return {};
    },

    GetItems: function (catId) {
        var $this = this;
        return {};
    },

    InitializeUI: function () {
        //build categories

        //bind category click event
    },
    ShowDrinks: function () {
        //build drinks
    }
}




To build above UI we are using following HTML

<div style="overflow-y: scroll; height: 250px" id="categoriesContainer">
                                                <div class="info-block block-info clearfix">
                                                    <div class="square-box pull-left">
                                                        <img class="categoryImage" src="images/drinks/milkshake.png" alt="" width="56" height="56" />
                                                    </div>
                                                    <h4 class="categoryName">Test Drink</h4>
                                                    <p class="categoryDescription">Refresh yourself with this cold drink</p>
                                                </div>
                                                <div class="info-block block-info clearfix">
                                                    <div class="square-box pull-left">
                                                        <span class="glyphicon glyphicon-user glyphicon-lg"></span>
                                                    </div>
                                                    <h4>Test Drink</h4>
                                                    <p>Mix with picolo</p>
                                                    <span>Price: $99</span>
                                                </div>
                                            </div>

On hovering the list item we change the color of the item to `gray(#E6E6E6)` using following CSS

.info-block:hover
{
    border:3px solid #f1685e;
    background-color: #E6E6E6;
}

On click of the list item we change the list item color to red(#f1685e) by simply applying following CSS class using javascript.

.info-block.current
{
    border:3px solid #f1685e;
    background-color: #f1685e;
}

$(".info-block").live("click", function () {
        $(".info-block").removeClass("current");
        $(this).addClass("current");
});

To load the json data into User Interface we will use following jquery code,
The _.map function is part of UnderScoreJs library, this function produces a new array of values by mapping each value in list. Here we are creating a new categories list array with id, name and image properties.

GetCategories: function () {
        return _.map(this.data, function (category) {
            return {
                id: category.categoryid,
                name: category.name,
                image: category.image
            };
        });
    },

To get only the categories from json we will use above jquery code.

var categoriesContainer = $("#categoriesContainer");
        var item = $(categoriesContainer.children(0)).first().clone();
        categoriesContainer.empty();
        var categories = this.GetCategories();
        var $this = this;
        $.each(categories, function (i, category) {
            console.log(category);
            var clone = $(item.clone());
            clone.prop("id", category.id);
            $(clone.find(".categoryName")).html(category.name);
            $(clone.find(".categoryImage")).attr("src", category.image);
            $(clone.find(".categoryDescription")).html(category.description);
            clone.click(function () {
                $this.SelectedCategory = parseInt($(this).prop("id"));
            });
            clone.appendTo(categoriesContainer);
        });


Above code iterates through all categories and appends the UI items to the container. Here using the jQuery `clone()` function we are cloning the first child element inside the   categoriesContainer`. Then we are setting its properties such as name, image and description using jQuery and then we are appending the cloned element to the `categoriesContainer`

In our prototype we have SelectedCategory property to get and set the selected category.

this.SelectedCategory = 1;

When we move to the next tab, to get the selected drink details we use the following code, here we are using the underscorejs filter function to get the selected category details.

clone.click(function () {
                $this.SelectedItem = parseInt($(this).prop("id"));

                //update name and price
                var item = _.filter($this.GetItems($this.SelectedCategory), function (itm) {
                    return itm.id == $this.SelectedItem;
                })[0];
                $this.Name = item.name + " - " + _.filter($this.data, function (category) {
                    return category.categoryid == $this.SelectedCategory;
                })[0].name;
                $this.Price = item.price;
            });

Then we bind these details to the UI.

 $("#showPayment").click(function () {
        $(".spnPrice").html(obj.Price);
        $(".spnDrinkName").html(obj.Name);
        $("#liPayment").tab("show");
});

Payment & Preparing drink

The preparing alert messages is just pseudo code which shows alert message that the payment has happened and user can order drink again.

$("#pourDrink").click(function () {
        alert("pouring the drink...");
        if (confirm("do you want to order again?")) {
            $("#liHome").tab("show");
        }
    });

Conclusion
By providing these steps I am suggesting that you can learn programming JavaScript by following the steps provided in this article.
If you think I’ve missed anything major (like maybe better javascript function), let me know in the comments.