JQuery

by MikeHogg 5. July 2012 09:49

 

On my third web project, I got the opportunity to dive into jquery a little more.   We were rewriting an existing site in MVC3.  One of my tasks was to reproduce a standard sort of “Locations” page.  I had some javascript to work from, but we were adding a new “Location Features” feature, and a GPS feature, and the existing javascript wasn’t in any shape to be extended.  I only needed a small form, and my only server side code, my Location Features MVC3 call, was a three liner LINQ query against an Entity Framework db, so most of the task was my opportunity to rewrite some old mess of long cryptic javascript function into jquery, and figuring out a good readable, maintainable code flow.    In the first page here you will see my standard style of using the MVC model binding, even for two properties, and a very short clean page of html, with my CSS file referenced in the beginning, and my JS file referenced at the end.

 

 

 

@model SomeBase.Models.LocatorModel
<link rel="stylesheet" href="@Url.Content("~/Content/css/locator.css")">
<div class="locatordiv">
    @using (Html.BeginForm("Locator", "Home", FormMethod.Post, new { id = "locator" }))
    {   
        <p>  Enter a city and state, or zip code below.</p>
                    
        @Html.HiddenFor(m => m.Gps)
        @Html.TextBoxFor(m => m.Zip, new { title = "Enter ZIP", @Class = "textbox" })
        
        <input type="submit" value="" class="findbutton" data-category="Find" data-event="Homepage Zipcode" />
        <a href="#" class="gpsbutton" onclick="do_geo();" title="GPS" data-category="Find" data-event="GPS"></a>
     
        <div id="gpsloading">Working ...<br /><img src="@Url.Content("~/Content/images/load-bar.gif")" /></div>     
    }  
</div>
<div id="maploading">
    <img src="@Url.Content("~/Content/images/load-circle.gif")" />
</div>
<div id="results"></div>     
<div id="mapDiv"></div>
    
<script type="text/javascript">
            var configMQAPIKey = '@Html.Raw(System.Configuration.ConfigurationManager.AppSettings["MQ:APIKey"].ToString())';
            var configMQOLOKey = '@Html.Raw(System.Configuration.ConfigurationManager.AppSettings["MQ:OLOKey"].ToString())';
            var configMQHostedDataTable = '@Html.Raw(System.Configuration.ConfigurationManager.AppSettings["MQ:HostedDatatable"].ToString())'; 
        </script>
        <script src='//www.mapquestapi.com/sdk/js/v7.0.s/mqa.toolkit.js?key=@Html.Raw(System.Configuration.ConfigurationManager.AppSettings["MQ:APIKey"].ToString())'></script>
        <script src="@Url.SomeContent("~/Content/js/locator.js")"></script>
        <script type="text/javascript" src="@Url.Content("~/Content/js/jquery.cookie.js")" ></script> 

The javascript wasn’t terribly complicated, but it was fun to get deeper into jquery and learn to use standard jquery element creation and manipulation methods, and the unobstrusive javascript pattern, as opposed to the old verbose javascript getelementById calls.   Here you will see my style of paying special attention to method and variable names, in place of comments.  I was taught that comments should be for WHY not WHAT, and if you name your objects clearly enough, you don’t need to comment WHAT you are doing.

 

 

function searchByGps() {
    $("#Zip").val(""); $("#Key").val("")
    search("https://www.mapquestapi.com/search/v1/radius" +
                    "?key=" + mq_key + "&radius=" + $("#inradius").val() + "&callback=processPOIs&maxMatches=" + inmatch +
           "&origin=" + encodeURIComponent($("#Gps").val()) + "&hostedData=" + intable);
} 
function searchByZip() {
    $("#Gps").val(""); $("#Key").val("")
    search("https://www.mapquestapi.com/search/v1/radius" +
                    "?key=" + mq_key + "&radius=" + $("#inradius").val() + "&callback=processPOIs&maxMatches=" + inmatch +
           "&origin=" + encodeURIComponent($("#Zip").val()) + "&hostedData=" + intable);
} 
                
function search(url){
    MQA.IO.doJSONP(url); 
}
function processPOIs(results) {
    if (results.searchResults != null && results.searchResults.length > 0) {
        drawPOIsOnMap(results.searchResults);
        drawResultTable(results.searchResults);
        
        if ($("#Key").val()) {
            $("#Zip").val(results.searchResults[0].fields.address + " " + results.searchResults[0].fields.city + ", " + 
                          results.searchResults[0].fields.state + " " + results.searchResults[0].fields.postal); 
        }
        $.ajax('/Home/GetLocationFeatures', {
            data: JSON.stringify(parseToEntityObjects(results.searchResults)),
            dataType: "json",
            type: "post",
            contentType: "application/json",
            success: function (featuredata) { processFeatures(featuredata, results.searchResults); }
        });
    } 
    else if (results.info && results.info.statuscode == 610) {
        // ambiguities
        // results.collections[1] is To, 0 is From
        $("#Gps").val(results.collections[0][0].latLng.lat + ',' + results.collections[0][0].latLng.lng);
        searchByGps();
    }
    else {
        $('#results .frame').html("<h1>Oops! We couldn’t find any results. Please try your search again.</h1>");
    }
}
function processOLOs(oloData, searchResults) {
    $.each(searchResults, function (i, result) { 
        if (oloData != null) {
            $.each(oloData.restaurants, function () {
                if (this.telephone == result.fields.Phone) {
                    var oloid = '#olo' + result.fields.RecordId;
                    $(oloid).append($("<a></a>", { href: this.url, "class": "ololinks", target: "_blank", text: "Place an Order" }));
                }                    
            });  }   }); }  
function processFeatures(featureData, searchResults) {
    $.each(searchResults, function (i, result) { 
        if (featureData != null) {
            $.each(featureData, function () {
                if (this.StoreNumber == result.fields.RecordId) {
                    var fid = '#feature' + result.fields.RecordId;
                    $(fid).append($("<a></a>", {href:this.Url, "class":"featurelinks", target:"_blank", text:this.Label}));
                }   });         }  });  }   
function drawResultTable(results) {
    $("#maploading").hide();
    $('#results').html("<h1>Search Results</h1>");
         
    $.each(results, function (i, result) {
            
        $("<div></div>", { "class": 'resultrow' })
                     .append("<p class='addressrowresult'>" +
                result.fields.address + "<br/ >" +
                result.fields.city + ", " + result.fields.state + "<br/ >" +
                result.fields.Phone + "<br /></p>")
            .append("<div>" + getRoundedDistance(result) + " Mi.    " + getMapItLink(result) + "</div>") 
            .append("<div class='olos' id='olo" + result.fields.RecordId + "'></div>")   // olo can find this span$(#olo#storenumber#) later
            .append("<div class='features' id='feature" + result.fields.RecordId + "'></div>") // feature can find this span$(#feature#storenumber#) later
            .appendTo("#results");
    }); }  
function parseToEntityObjects(data) {
    var locations = [];
    $.each(data, function () {
        locations.push({
            StoreNumber: this.fields.RecordId,
            Address1: this.fields.address,
            City: this.fields.city,
            ZipCode: this.fields.postal,
            Phone: this.fields.Phone
        });
    });
    return locations;
}
function getRoundedDistance(result) { 
    if (result.distance > 10) {
        return Math.round(result.distance);
    } else if (result.distance > 1) {
        return Math.round(result.distance * 10) / 10;
    }  
    return Math.round(result.distance * 100) / 100; 
}
function getMapItLink(result){ 
    var destination = result.fields.address + ',' + result.fields.city + ',' + result.fields.state + ',' + result.fields.postal;
    var link = $("<a>", { href: "#", "class": "mapitlink", title: "Map It!", onclick: "mapIt(getOrigin(), '" + destination + "');return false;", text: "Map It!" })
                .attr({ "data-category": "Find", "data-event": "Map Quest" });
    return $('<div>').append(link.clone()).html();  // hack to get string not js object for mqa
}                    
function getPOIRollover(result) {
    var rollover = $("<div></div>", { "class": "poirollover" }).append($('<h4></h4>').text(result.fields.N))
        .append($('<span></span>').text(result.fields.address))
        .append($('<br />')).append($('<span></span').text(result.fields.city + ", " + result.fields.state))
        .append($('<br />')).append($('<span></span>').text(result.fields.Phone))
        .append($('<br />')).append($('<span></span>').text(getRoundedDistance(result) + " Mi.  "))
        .append(getMapItLink(result));
    return $('<div>').append(rollover.clone()).html(); // hack to get string not js object for mqa
}
function mapIt(origin, destination) {
    // build a url and send to the Directions Web Service
    MQA.IO.doJSONP("http://www.mapquestapi.com/directions/v1/route?" +
              "key=" + mq_key + "&" +
              "from=" + origin + "&" +
              "to=" + destination + "&" +
              "shapeFormat=raw&generalize=0.1&" +
              "callback=drawDirections");
}

 

My CSS file was mostly empty at the start.  But I wanted to make it easy to add style later, by applying classes and these empty placeholders for just about every element that we might want.

 

 

.locatordiv
{
    text-align:center; 
    margin:20px;
} 
.gpsbutton {
       background:url(../images/icon-gps.png) no-repeat;      
       background-size:42px auto; 
       padding:21px;    
} 
#gpsloading
{    display:none;
}
#maploading
{     display: none;  
}
#mapDiv
{    float:left; 
}
#results
{    float:left;
}
.resultrow
{    margin:20px;
}
.mapitlink
{    
}
.poirollover
{    width:150px;
}
.olos
{
}
.ololinks
{
}
.features
{    display:block;
}
.featurelinks
{    display:block;
}
.addressrowresult
{    width: 210px;
}
#directionsdiv
{    
}
.directionrow
{    
}

Tags:

Javascript | JQuery

Add comment

biuquote
  • Comment
  • Preview
Loading

About Mike Hogg

Mike Hogg is a c# developer in Brooklyn.

More Here

Favorite Books

This book had the most influence on my coding style. It drastically changed the way I write code and turned me on to test driven development even if I don't always use it. It made me write clearer, functional-style code using more principles such as DRY, encapsulation, single responsibility, and more. amazon.com

This book opened my eyes to a methodical and systematic approach to upgrading legacy codebases step by step. Incrementally transforming code blocks into testable code before making improvements. amazon.com

More Here