Telerik blogs

In this post, we'll see how to build upon our jQuery Mobile and Icenium knowledge to build a common web development component - a survey.

Have you ever ate at a restaurant and been asked to complete a survey? Normally the experience involves calling some 1-800 number and interacting with a robotic voice. Not fun.

In this article we'll build a better experience - a survey embedded into a hybrid application. This gives the user the convenience of filling out the survey on their device, the restaurant the ability to deploy the app through app stores, and us the ability to develop the survey using familiar technologies: HTML, CSS, and JavaScript.

We'll start by discussing the widgets jQuery Mobile provides to build mobile friendly forms quickly, then use use these widgets to build the survey UI.

Next, we'll figure out where to send the form data. Normally this involves a complex back end with a database backed API - a bit much for this example. Luckily, Icenium Everlive provides a cloud based back end that we can setup in minutes. We'll tie our form into Everlive to collect results and display them within seconds.

Let's get started.

Building Forms with jQuery Mobile

We'll start by getting the actual survey UI created. jQuery Mobile provides the following eight widgets for building forms:

jQuery Mobile widgets can be created declaratively by adding data-role attributes to HTML elements. However, most form widget will auto-enhance without any configuration at all. For example consider the following <select>:

<select>
    <option>One</option>
    <option>Two</option>
    <option>Three</option>
</select>

When included in jQuery Mobile, this will display as follows:

Display of select elements in jQuery Mobile

You can see that jQuery Mobile automatically enhanced the element into a bigger mobile-friendly version of a <select>. If you want to disable the auto-enhancement you can an add a data-role="none" attribute to the element. This display the element using the browser native display.

<select data-role="none">
    <option>One</option>
    <option>Two</option>
    <option>Three</option>
</select>

In our case we'll want to use the auto-enhancement to build this form quickly.

Now that we've seen the widgets available, let's use them to build our survey. We'll be asking users three questions:

  • What location they visited? (We'll assume this restaurant has North, South, and West locations.)
  • Whether they ordered an appetizer.
  • How they would rate their experience on a scale of 1 to 5.

Here's the form we will present to the user to complete these questions.

<p><strong>Please complete the following survey.</strong></p>
<form>
    <div>
        <!-- Create a controlgroup widget -->
        <fieldset data-role="controlgroup" data-type="horizontal">
            <legend>Which location did you visit?</legend>
            <input type="radio" name="location" id="location-north" value="north" checked>
            <label for="location-north">North</label>
            <input type="radio" name="location" id="location-south" value="south">
            <label for="location-south">South</label>
            <input type="radio" name="location" id="location-west" value="west">
            <label for="location-west">West</label>
        </fieldset>
    </div>

    <div>
        <!-- Create a switch widget -->
        <!-- Switches are consider a type of slider by the framework therefore -->
        <!-- data-role="slider" is used. The framework knows to convert -->
        <!-- select elements with data-role="slider" into switches. --> 
        <label for="appetizer">Did you order an appetizer?</label>
        <select name="appetizer" id="appetizer" data-role="slider">
            <option value="no">No</option>
            <option value="yes">Yes</option>
        </select>
    </div>

    <div>
        <!-- Create a slider widget -->
        <label for="rating">Please rate your overall experience from 1 to 5:</label>
        <input type="range" name="rating" id="rating" value="3"
          min="1" max="5" step="1" data-highlight="true">
    </div>

    <div>
        <button>Submit</button>
    </div>
</form>

This displays as follows in Icenium's iOS simulator:

Display of the form built with jQuery Mobile in Icenium's iOS simulator

Note: In order for the switch and slider widgets to work with a mouse in Icenium's simulators you need to turn on touch event emulation in Chrome.

As you can see, jQuery Mobile makes it easy to build custom mobile friendly forms with little effort - we didn't even have to write a single line of JavaScript or CSS.

But, now what? We have a form but where do we send the data?

Where to Send the Data?

Web developers are comfortable with client side technologies, and the thought of setting up a full backend is overwhelming. What languages and technologies are you going to write the back end with? What type of database are you going to store the data in? Where are you going to host the backend? What do some of these questions even mean?

Icenium Everlive alleviates these concerns by offering a backend as a service. Your data goes in the cloud and you get APIs to manage and configure it with ease. You don't have to worry about how to build your backend, host your backend, or scale it when your restaurant survey goes viral.

Let's see how we can tie our form into Everlive.

Setting up Everlive

For our hybrid app, the first step to using Everlive is to download the JavaScript SDK and import it into our project. You can download the JavaScript SDK at http://docs.telerik.com/platform/backend-services/development/javascript-sdk/introduction. This is shown below.

Downloading Everlive's JavaScript SDK

As you can see Everlive has SDKs for multiple other platforms. Therefore it's possible to store and retrieve the same data from completely different technologies - for now though, we'll be concentrating the on the JavaScript SDK.

To use the SDK we have to import it into our Icenium project. Within Icenium Mist, select Add --> Existing Files as shown below.

Adding new files to an Icenium project

From the dialog that pops up you can select files from your file system, or just drag and drop the file into the dialog. We'll be using everlive.all.min.js.

Adding the Everlive SDK file

You can also drag and drop files within Icenium's project navigator to organize your project. Let's drag everlive.all.min.js into the scripts folder. Then we can import the JavaScript SDK with the following script tag.

<script src="scripts/everlive.all.min.js"></script>

Now that we have the JavaScript SDK imported, we need one more line of code to initialize the SDK. Create a new main.js in your project's scripts folder and add the following:

new Everlive({ apiKey: '#YOUR-KEY-HERE' });

You can get your API key by viewing your project on http://everlive.com.

Our last step is configuring the back end. Everlive backends are made up of content types, which are like to a schemas in relational databases. If you visit your project's dashboard in Everlive you'll see that a few content types are already created for you. The image below shows the dashboard of a new Everlive project. Note the already existing content types of Activities, Comments, Users, Roles, Files, and Devices.

Dashboard for an Everlive project

These content types give you an excellent starting point for implementing common tasks such as user management and file storage. For our purposes however, we'll want to create a new content type from scratch. Click the "Create a Content Type" button and configure a new Ratings content type with the fields shown below.

Adding the ratings content type

This gives our content type three new fields - location, appetizer, and rating - that map to the fields on our survey. And with that, our back end setup is complete! No complex database to setup or maintain.

Now that we have a back end the next step is to connect it to our front end. We'll see how this is easily accomplished with a few lines of JavaScript.

Sending Data From a Form to Everlive.

Everlive's JavaScript SDK that we included has APIs for performing CRUD (Create Read Update Delete) operations on our application's content types.

To tie our survey to our back end, we have to listen for the survey's form submission, grab the data we need, and send it to Everlive. The code below does this; place it in your app's scripts/main.js file.

// Add an event listener for the survey form's submission.
$('form').on('submit', function(event) {

    // Prevent the default form submission as we'll be sending the data to Everlive.
    event.preventDefault();

    // Retrieve the data from the form.
    var data = {
        location: $(this.location).filter(':checked').val(),
        appetizer: $(this.appetizer).val() == "yes",
        rating: $(this.rating).val()
    };

    // Use jQuery Mobile to show a loading indicator while we send data
    // to our Everlive backend.
    $.mobile.loading('show', { text: 'Processing...', textVisible: true });

    // Create a new rating with our project's "Ratings" content type using
    // the SDK's create method.
    Everlive.$.data('Ratings').create(data,

        // Function to run on a successful transfer.
        function(data){

            // Hide the loading indicator now that processing is complete.
            $.mobile.loading('hide');

            // Take the user to another page to tell them the submission worked.
            $.mobile.changePage('#success');
        },

        // Function to run on erred transfers.
        function(error){

            // Let the user know if something went wrong.
            alert('Sorry, an error occurred processing your survey. Please try again later.');
        }
    );

    return false;
});

On successful submission, this script uses jQuery Mobile's changePage() method to send the user to a success page. We'll use the following success page for now. Add this to the project's index.html.

<div data-role="page" id="success">
    <div data-role="header">
        <h1>Thanks!</h1>
    </div>
    <div data-role="content">
        <p>Your survey was successfully processed. Thank you.</p>
        <a href="#results" data-role="button">View Results</a>
    </div>
</div>

Now when the user submits our survey they will see the following.

Display of the form built with jQuery Mobile in Icenium's iOS simulator

And in Everlive, if we look at our rating content type we have the following entry:

Display of the rating data in Everlive

That's all there is to it. As users fill out our survey our back end will be populated with the data automatically.

But what good is a ton of raw data? The good news is Everlive makes it just as easy to get data out as it was to put in it.

Retrieving Data From Everlive

As we discussed, Everlive's JavaScript SDK has APIs for all CRUD operations. To get data out of Everlive, we can use the getById() method to get an individual rating, or the get() method to get all of them. For our survey, we want to aggregate all data, therefore we'll use get(). The following invokes get() to retrieve all Ratings.

Everlive.$.data('Ratings').get();

This does an AJAX request to retrieve the data and returns a promise object that is resolved when the data has returned. In simple terms, this means you can attach functions to run when the data is successfully retrieved, and when something goes wrong. This is shown below.

Everlive.$.data('Ratings').get()
    .then(
        // Success callback
        function(data) {
            alert(JSON.stringify(data));
        },
        // Error callback
        function(error) {
            alert(JSON.stringify(error));
        }
    );

After users fill out a survey they like to see the aggregated results of the form they just filled out. Now that we have a means of retrieving the data, let's add a means of displaying it in our UI.

First we'll add a link from our success page to a new results page.

<div data-role="page" id="success">
    <div data-role="header">
        <h1>Thanks!</h1>
    </div>
    <div data-role="content">
        <p>Your survey was successfully processed. Thank you.</p>

        <!-- Link to results page -->
        <a href="#results" data-role="button">View Results</a>
    </div>
</div>

Next, when the user clicks the link to the results page, we need to load the results and show them to the user. How will we know when the user visits the results page? jQuery Mobile fires a number of events as the user interacts with pages in the application. For our purposes, we'll use the pageshow event.

First, here's a starting point for the new results page:

<div data-role="page" id="results">
    <div data-role="header">
        <h1>Results</h1>
    </div>
    <div data-role="content">
        <!-- We'll add some tables for the results themselves here -->
    </div>
</div>

Then in JavaScript will listen for pageshow event on this new page and load our data.

// Subscribe to the pageshow event on the results page.
$('#results').on('pageshow', function() {

    // Show a loading message while the retrieve call occurs.
    $.mobile.loading('show', { text: 'Loading results...', textVisible: true });

    // Retrieve the ratings data from Everlive.
    Everlive.$.data('Ratings').get()
        .then(
            // When the data loads call a function to display the data.
            // We'll look at what this function does momentarily.
            displayResults,

            // Let the user know if something went wrong.
            function(error) {
                alert('Sorry, loading the survey results failed.');
            }
        );
});

This gets us the data, but we still have to show it to the user. For simplicity, we'll build a few minimal tables on the results page. Place the following in the content of the results page.

<table class="ui-table">
    <thead>
        <tr>
            <th colspan="2">Location</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>North</td>
            <td id="results-north"></td>
        </tr>
        <tr>
            <td>South</td>
            <td id="results-south"></td>
        </tr>
        <tr>
            <td>West</td>
            <td id="results-west"></td>
        </tr>
    </tbody>
</table>

<table class="ui-table">
    <thead>
        <tr>
            <th colspan="2">Appetizer</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Yes</td>
            <td id="results-yes"></td>
        </tr>
        <tr>
            <td>No</td>
            <td id="results-no"></td>
        </tr>
    </tbody>
</table>

<table class="ui-table">
    <thead>
        <tr>
            <th colspan="2">Overall Rating</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>One</td>
            <td id="results-1"></td>
        </tr>
        <tr>
            <td>Two</td>
            <td id="results-2"></td>
        </tr>
        <tr>
            <td>Three</td>
            <td id="results-3"></td>
        </tr>
        <tr>
            <td>Four</td>
            <td id="results-4"></td>
        </tr>
        <tr>
            <td>Five</td>
            <td id="results-5"></td>
        </tr>
    </tbody>
</table>

Then, we'll use the following function to aggregate the data and populate the tables:

function displayResults(data) {

    // Create a counter for each result. Start all counters at 0.
    var results = {
        location: { north: 0, south: 0, west: 0 },
        appetizer: { yes: 0, no: 0 },
        rating: { '1': 0, '2': 0, '3': 0, '4': 0, '5': 0 }
    };

    // Loop over each individual result, increment the appropriate counters.
    data.result.forEach(function(result) {
        results.location[result.location]++;
        results.appetizer[(result.appetizer ? 'yes' : 'no')]++;
        results.rating[result.rating]++;
    });

    // Fill the table cells with the data as appropriate.
    $('#results-north').text(results.location.north);
    $('#results-south').text(results.location.south);
    $('#results-west').text(results.location.west);
    $('#results-yes').text(results.appetizer.yes);
    $('#results-no').text(results.appetizer.no);
    $('#results-1').text(results.rating['1']);
    $('#results-2').text(results.rating['2']);
    $('#results-3').text(results.rating['3']);
    $('#results-4').text(results.rating['4']);
    $('#results-5').text(results.rating['5']);

    // Hide the loading indicator now that the data is visible.
    $.mobile.loading('hide');
};

Now when the user clicks view results they will see the following:

Display of the results

That's all it took to retrieve all data and get it on the screen. Admittedly, the display is very basic, but it gets the job done for a demonstration. If you're looking for rich ways to display your data such as bar graphs and pie charts, check out Kendo UI's data visualization libraries.

Where To Go From Here

In this article we saw how to build a form using jQuery Mobile and connect it to an Everlive backend. The user is now able to complete a survey and see aggregated results automatically.

The full source of our sample application is in this GitHub repository. Feel free to poke around in the source, or fork the repo and make it your own.

Looking to learn more? The following resources can help you explore all that jQuery Mobile and Everlive have to offer.


TJ VanToll
About the Author

TJ VanToll

TJ VanToll is a frontend developer, author, and a former principal developer advocate for Progress.

Comments

Comments are disabled in preview mode.