Blog Archives

The Prototype Pattern – Techniques, Strategies and Patterns for Structuring JavaScript Code

Using the JavaScript Prototype Pattern

This is the 2nd post in a series on techniques, strategies and patterns for writing JavaScript code. In my previous post I introduced what I call “function spaghetti code” and explained some of the problems it introduces. I also talked about the impact of global variables and how closures add a much needed solution. In this post I’ll introduce the Prototype Pattern and show how it relies on built-in functionality in the JavaScript language.

I’ve worked through some of the patterns I’m covering in this series with my good friend John Papa over Skype and we’ve talked about pros and cons of different approaches. For example, he initially recommended defining multiple variables using a single var based on JSLint suggestions (that was covered in the previous post) and I agreed that it was a better approach than using var for every variable. It’s interesting how code evolves with feedback from multiple people. John and I have definitely come to enjoy working with a few different patterns and although the Prototype Pattern isn’t in my favorites list, I’ve always felt that it’s good to understand and know the different options out there. That’s why I decided to include it in this series.

The Prototype Pattern can be broken out into two main sections including a constructor section and a prototype section. Prototyping allows functions and properties to be associated with objects. However, instead of each object instance getting a copy of all functions/properties each time an object is created, only one set of functions/properties exists across all objects resulting in less memory consumption. In other words, functions and properties are defined once per prototype rather than once per object.

As a quick review, I showed the following code in a previous post. The code simply lists all functions directly with no encapsulation and defines several global variables. While the code works fine this way, I’ll examine how we can restructure it to follow the Prototype Pattern.

window.onload = function () {
    eqCtl = document.getElementById('eq');
    currNumberCtl = document.getElementById('currNumber');
};

var eqCtl,
    currNumberCtl,
    operator,
    operatorSet = false,
    equalsPressed = false,
    lastNumber = null;

function add(x,y) {
    return x + y;
}

function subtract(x, y) {
    return x - y;
}

function multiply(x, y) {
    return x * y;
}

function divide(x, y) {
    if (y == 0) {
        alert("Can't divide by 0");
        return 0;
    }
    return x / y;
}

function setVal(val) {
    currNumberCtl.innerHTML = val;
}

function setEquation(val) {
    eqCtl.innerHTML = val;
}

function clearNumbers() {
    lastNumber = null;
    equalsPressed = operatorSet = false;
    setVal('0');
    setEquation('');
}

function setOperator(newOperator) {
    if (newOperator == '=') {
        equalsPressed = true;
        calculate();
        setEquation('');
        return;
    }

    //Handle case where = was pressed
    //followed by an operator (+, -, *, /)
    if (!equalsPressed) calculate();
    equalsPressed = false;
    operator = newOperator;
    operatorSet = true;
    lastNumber = parseFloat(currNumberCtl.innerHTML);
    var eqText = (eqCtl.innerHTML == '') ?
        lastNumber + ' ' + operator + ' ' :
        eqCtl.innerHTML + ' ' + operator + ' ';
    setEquation(eqText);
}

function numberClick(e) {
    var button = (e.target) ? e.target : e.srcElement;
    if (operatorSet == true || currNumberCtl.innerHTML == '0') {
        setVal('');
        operatorSet = false;
    }
    setVal(currNumberCtl.innerHTML + button.innerHTML);
    setEquation(eqCtl.innerHTML + button.innerHTML);
}

function calculate() {
    if (!operator || lastNumber == null) return;
    var currNumber = parseFloat(currNumberCtl.innerHTML),
        newVal = 0;
    //eval() would've made this a whole lot simpler
    //but didn't want to use it in favor of a more
    //"robust" set of methods to demo patterns
    switch (operator) {
        case '+':
            newVal = add(lastNumber, currNumber);
            break;
        case '-':
            newVal = subtract(lastNumber, currNumber);
            break;
        case '*':
            newVal = multiply(lastNumber, currNumber);
            break;
        case '/':
            newVal = divide(lastNumber, currNumber);
            break;
    }
    setVal(newVal);
    lastNumber = newVal;
}

 

To start using the Prototype Pattern you need to first create a constructor as shown next. The constructor can accept one or more parameters and define any variables that the object needs. Note that the variables are scoped to the object rather than to the global scope.

var Calculator = function (tb, eq) {
    this.eqCtl = document.getElementById(eq);
    this.currNumberCtl = document.getElementById(tb);
    this.operator = null;
    this.operatorSet = false;
    this.equalsPressed = false;
    this.lastNumber = null;
};


Once the constructor is defined a prototype can be created using the prototype keyword. Although you can create a prototype for each function, it’s more convenient (and less typing) to take advantage of JSON-style syntax where the function name represents the JSON property name and the value represents the function. An example of defining two functions in a prototype is shown next. Notice that each function is separated with a comma just as you would separate properties defined in a normal JSON object. It’s officially called a JavaScript object literal, but if you’re familiar with JSON it uses the same standard syntax (thanks to Craig Stuntz for clarifying that):

Calculator.prototype = {

    add: function (x, y) {
        return x + y;
    },

    subtract: function (x, y) {
        return x - y;
    }
}


The original function-based calculator code shown earlier can be refactored to follow the Prototype Pattern as shown shown next. A prototype is created for the Calculator object and functions/properties are defined within the prototype using JavaScript object literal syntax.

Calculator.prototype = {

    add: function (x, y) {
        return x + y;
    },

    subtract: function (x, y) {
        return x - y;
    },

    multiply: function (x, y) {
        return x * y;
    },

    divide: function (x, y) {
        if (y == 0) {
            alert("Can't divide by 0");
        }
        return x / y;
    },

    setVal: function(val) {
        this.currNumberCtl.innerHTML = val;
    },

    setEquation: function (val) {
        this.eqCtl.innerHTML = val;
    },

    clearNumbers: function () {
        this.lastNumber = null;
        this.equalsPressed = this.operatorSet = false;
        this.setVal('0');
        this.setEquation('');
    },

    setOperator: function (newOperator) {
        if (newOperator == '=') {
            this.equalsPressed = true;
            this.calculate();
            this.setEquation('');
            return;
        }

        //Handle case where = was pressed
        //followed by an operator (+, -, *, /)
        if (!this.equalsPressed) this.calculate();
        this.equalsPressed = false;
        this.operator = newOperator;
        this.operatorSet = true;
        this.lastNumber = parseFloat(this.currNumberCtl.innerHTML);
        var eqText = (this.eqCtl.innerHTML == '') ?
            this.lastNumber + ' ' + this.operator + ' ' :
            this.eqCtl.innerHTML + ' ' + this.operator + ' ';
        this.setEquation(eqText);
    },

    numberClick: function () {
        var button = (event.target) ? event.target : event.srcElement;
        if (this.operatorSet == true || this.currNumberCtl.innerHTML == '0') {
            this.setVal('');
            this.operatorSet = false;
        }
        this.setVal(this.currNumberCtl.innerHTML + button.innerHTML);
        this.setEquation(this.eqCtl.innerHTML + button.innerHTML);
    },

    calculate: function () {
        if (!this.operator || this.lastNumber == null) return;
        var displayedNumber = parseFloat(this.currNumberCtl.innerHTML)
            newVal = 0;
        //eval() would've made this a whole lot simpler
        //but didn't want to use it in favor of a more
        //"robust" set of methods to demo patterns
        switch (this.operator) {
            case '+':
                newVal = this.add(this.lastNumber, displayedNumber);
                break;
            case '-':
                newVal = this.subtract(this.lastNumber, displayedNumber);
                break;
            case '*':
                newVal = this.multiply(this.lastNumber, displayedNumber);
                break;
            case '/':
                newVal = this.divide(this.lastNumber, displayedNumber);
                break;
        }
        this.setVal(newVal);
        this.lastNumber = newVal;
    }
};


To use the Calculator object, create a new instance and pass the names of the HTML container objects into the constructor (the container objects identify the IDs of controls used to display calculations – see the HTML code below):

var calc = null;
window.onload = function () {
    calc = new Calculator('currNumber', 'eq');
};


The HTML used to render the calculator can reference the calc object created when the page loads. The following code demonstrates how this can be done to handle events as different div elements are clicked. I normally prefer to wire-up events to event handlers using jQuery in “real-world” applications to keep the HTML clean but wanted to focus on JavaScript patterns and avoid introducing additional libraries for this post. I’m not a big fan of defining onclick and other event handlers directly on HTML elements but let it slide for this post.

<div class="Calculator">
    <div class="CalculatorHead">
        <div id="eq" class="Equation"></div>
        <div id="currNumber" class="CurrentNumber">0</div>
    </div>
    <div>
        <div class="Button" onclick="calc.numberClick(event);">7</div>
        <div class="Button" onclick="calc.numberClick(event);">8</div>
        <div class="Button" onclick="calc.numberClick(event);">9</div>
        <div class="Button" onclick="calc.setOperator('/');">/</div>
        <div class="Button rowspan2" onclick="calc.clearNumbers();">C</div>
    </div>
    <div>
        <div class="Button" onclick="calc.numberClick(event);">4</div>
        <div class="Button" onclick="calc.numberClick(event);">5</div>
        <div class="Button" onclick="calc.numberClick(event);">6</div>
        <div class="Button" onclick="calc.setOperator('*');">*</div>
    </div>
    <div>
        <div class="Button" onclick="calc.numberClick(event);">1</div>
        <div class="Button" onclick="calc.numberClick(event);">2</div>
        <div class="Button" onclick="calc.numberClick(event);">3</div>
        <div class="Button" onclick="calc.setOperator('-')">-</div>
        <div class="Button rowspan2" onclick="calc.setOperator('=');">=</div>
    </div>
    <div>
        <div class="Button colspan2" onclick="calc.numberClick(event);">0</div>
        <div class="Button" onclick="calc.numberClick();">.</div>
        <div class="Button" onclick="calc.setOperator('+');">+</div>
    </div>
</div>

 

The Prototype Pattern provides a nice way to structure JavaScript code but there are several other roads you can travel if desired. In this next post I’ll talk about the Revealing Module Pattern and explain how it can be used.

Demos of all the patterns covered in this series can be downloaded below.

Download Code

Creating a Line Chart using the HTML 5 Canvas

The HTML 5 canvas is capable of rendering lines, shapes, images, text and more without relying on a plugin. Although the canvas element isn’t supported by older browsers, the latest version of all major browsers (IE, Safari, Chrome, Firefox and Opera) now support the canvas making it an option for rendering charts, graphs and other types of visual data. In cases where a browser doesn’t support the canvas, a fallback can be provided that renders data using Silverlight, Flash or another type of plugin.

In a previous post I walked through the fundamentals of using the HTML 5 canvas to render different types of shapes. In this post I’ll discuss how the canvas can be used to render a line chart using JavaScript. An example of the chart that will be discussed is shown next:

 

To render the chart a JavaScript object named CanvasChart was created that handles rendering all of the lines, shapes and text shown above. An example of defining CanvasChart settings and calling its render() function is show next. The render() function accepts the canvas element ID as well as a JSON object that defines chart properties and data to be used in the rendering process.

<!DOCTYPE html>
<html>
<head>
    <title>Canvas Chart Demo</title>
    <script src="Scripts/jquery-1.6.min.js" type="text/javascript"></script>
    <script src="Scripts/canvasChart.js" type="text/javascript"></script>
    <script type="text/javascript">

        $(document).ready(function () {
            var dataDef = { title: "US Population Chart",
                            xLabel: 'Year',
                            yLabel: 'Population (millions)',
                            labelFont: '19pt Arial',
                            dataPointFont: '10pt Arial',
                            renderTypes: [CanvasChart.renderType.lines, CanvasChart.renderType.points],
                            dataPoints: [{ x: '1790', y: 3.9 },
                                         { x: '1810', y: 7.2 },
                                         { x: '1830', y: 12.8 },
                                         { x: '1850', y: 23.1 },
                                         { x: '1870', y: 36.5 },
                                         { x: '1890', y: 62.9 },
                                         { x: '1910', y: 92.2 },
                                         { x: '1930', y: 123.2 },
                                         { x: '1950', y: 151.3 },
                                         { x: '1970', y: 203.2 },
                                         { x: '1990', y: 248.7 },
                                         { x: '2010', y: 308.7}]
                           };
            CanvasChart.render('canvas', dataDef);
        });

    </script>
</head>
<body style="margin-left:50px;margin-top:50px;">
    <canvas id="canvas" width="800" height="600"></canvas>
</body>
</html>


While the CanvasChart object is only a prototype at this point, it demonstrates several key features of the canvas element that can be used in applications including rendering lines, shapes, gradients, text and even transformed text. Let’s take a look at how the CanvasChart object was created.

Rendering Gradients and Text

The code for the CanvasChart object is located in a file named canvasChart.js. The code starts by defining a CanvasChart object that exposes two members named renderType and render. renderType is used to define what will be rendered on the chart (currently it supports rendering lines and points) while render() is used to render the data on the canvas as well as the associated labels for the x and y axes. The skeleton code for CanvasObject is shown next:

var CanvasChart = function () {
    var ctx;
    var margin = { top: 40, left: 75, right: 0, bottom: 75 };
    var chartHeight, chartWidth, yMax, xMax, data;
    var maxYValue = 0;
    var ratio = 0;
    var renderType = { lines: 'lines', points: 'points' };

    return {
        renderType: renderType,
        render: render
    };
} ();

 

The render() function accepts the canvas ID within the page as well as a JSON object that defines details about labels, font sizes, data points and more:

var render = function(canvasId, dataObj) {
    data = dataObj;
    getMaxDataYValue();
    var canvas = document.getElementById(canvasId);
    chartHeight = canvas.attr('height');
    chartWidth = canvas.attr('width');
    xMax = chartWidth - (margin.left + margin.right);
    yMax = chartHeight - (margin.top + margin.bottom);
    ratio = yMax / maxYValue;
    ctx = canvas.getContext("2d");
    renderChart();
}

 

The function starts by assigning the dataObj parameter to a variable within the CanvasChart object and then calls an internal function named getMaxDataYValue(). The getMaxDataYValue() function determines the maximum Y value for the data points. From there, the render() function locates the target canvas element within the page, calculates width and height values, and accesses the canvas’s 2D context that will be used to draw. Finally, a call is made to renderChart() to start the rendering process.

The renderChart() function orchestrates different drawing functions and handles rendering the background, lines, labels and data by calling the respective functions:

var renderChart = function () {
    renderBackground();
    renderText();
    renderLinesAndLabels();

    //render data based upon type of renderType(s) that client supplies
    if (data.renderTypes == undefined || data.renderTypes == null) data.renderTypes = [renderType.lines];
    for (var i = 0; i < data.renderTypes.length; i++) {
        renderData(data.renderTypes[i]);
    }
}

 

Different canvas features are used such as gradients and transforms in the CanvasChart object. For example, the renderBackground() function shows how linear gradients can be created:

var renderBackground = function () {
    var lingrad = ctx.createLinearGradient(margin.left, margin.top, xMax - margin.right, yMax);
    lingrad.addColorStop(0.0, '#D4D4D4');
    lingrad.addColorStop(0.2, '#fff');
    lingrad.addColorStop(0.8, '#fff');
    lingrad.addColorStop(1, '#D4D4D4');
    ctx.fillStyle = lingrad;
    ctx.fillRect(margin.left, margin.top, xMax - margin.left, yMax - margin.top);
    ctx.fillStyle = 'black';
}

 

The renderBackground() function uses the 2D context’s createLinearGradient() function to define a gradient that has 4 gradient stops. Once the gradient is defined it is assigned to the fillStyle property and then rendered to a rectangular area using the fillRect() function.

CanvasChart also demonstrates how text can be manipulated using transforms. The text displayed on the Y axis is rotated so that it displays vertically:

 

image

 

This is accomplished by using the canvas element’s rotate transform functionality which is found in the renderText() function:

var renderText = function renderText() {
    var labelFont = (data.labelFont != null) ? data.labelFont : '20pt Arial';
    ctx.font = labelFont;
    ctx.textAlign = "center";

    //Title
    var txtSize = ctx.measureText(data.title);
    ctx.fillText(data.title, (chartWidth / 2), (margin.top / 2));

    //X-axis text
    txtSize = ctx.measureText(data.xLabel);
    ctx.fillText(data.xLabel, margin.left + (xMax / 2) - (txtSize.width / 2), yMax + (margin.bottom / 1.2));

    //Y-axis text
    ctx.save();
    ctx.rotate(-Math.PI / 2);
    ctx.font = labelFont;
    ctx.fillText(data.yLabel, (yMax / 2) * -1, margin.left / 4);
    ctx.restore();
}

 

The key section of this code is the call to ctx.save() (toward the bottom of the function shown above) which saves the current state of the canvas so that it can be restored. This is necessary so that the entire canvas isn’t rotated. Once the current canvas state is saved, a call to the rotate() function is made to rotate the canvas. The text is then drawn for the vertical axis using the fillText() function. Once the rotated text is rendered the canvas is restored back to its saved state (the state before the rotate transform was applied and the text was rendered).

After the x and y axis text is rendered, the CanvasChart object makes a call to renderLinesAndLabels() to handle rendering the horizontal and vertical lines.

var renderLinesAndLabels = function renderLinesAndLabels() {
    //Vertical guide lines
    var yInc = yMax / data.dataPoints.length;
    var yPos = 0;
    var yLabelInc = (maxYValue * ratio) / data.dataPoints.length;
    var xInc = getXInc();
    var xPos = margin.left;
    for (var i = 0; i < data.dataPoints.length; i++) {
        yPos += (i == 0) ? margin.top : yInc;
        //Draw horizontal lines
        drawLine(margin.left, yPos, xMax, yPos, '#E8E8E8');

        //y axis labels
        ctx.font = (data.dataPointFont != null) ? data.dataPointFont : '10pt Calibri';
        var txt = Math.round(maxYValue - ((i == 0) ? 0 : yPos / ratio));
        var txtSize = ctx.measureText(txt);
        ctx.fillText(txt, margin.left - ((txtSize.width >= 14)?txtSize.width:10) - 7, yPos + 4);

        //x axis labels
        txt = data.dataPoints[i].x;
        txtSize = ctx.measureText(txt);
        ctx.fillText(txt, xPos, yMax + (margin.bottom / 3));
        xPos += xInc;
    }

    //Vertical line
    drawLine(margin.left, margin.top, margin.left, yMax, 'black');

    //Horizontal Line
    drawLine(margin.left, yMax, xMax, yMax, 'black');
}

 

Lines are normally drawn using the 2D context’s moveTo() and lineTo() functions which I wrapped in a function named drawLine() to simplify the process:

var drawLine = function drawLine(startX, startY, endX, endY, strokeStyle, lineWidth) {
    if (strokeStyle != null) ctx.strokeStyle = strokeStyle;
    if (lineWidth != null) ctx.lineWidth = lineWidth;
    ctx.beginPath();
    ctx.moveTo(startX, startY);
    ctx.lineTo(endX, endY);
    ctx.stroke();
    ctx.closePath();
}


At this point the canvas looks like the following:

image

Rendering Data

Once the labels and lines are rendered, CanvasChart handles rendering the data points by calling a function named renderData(). This function handles iterating through the JSON   data points and drawing lines, points or both depending upon the settings passed to CanvasChart’s render() function. Lines are drawn to connect the different data points through calls to the drawLine() function shown earlier while circles are drawn for specific data points by making calls to the 2D context’s arc() function. The circles that are rendered have a radial gradient applied to them using the createRadialGradient() function:

 

var renderData = function renderData(type) {
    var xInc = getXInc();
    var prevX, prevY = 0;

    for (var i = 0; i < data.dataPoints.length; i++) {
        var pt = data.dataPoints[i];
        var ptY = (maxYValue - pt.y) * ratio;
        if (ptY < margin.top) ptY = margin.top;
        var ptX = (i * xInc) + margin.left;

        if (i > 0 && type == renderType.lines) {
            //Draw connecting lines
            drawLine(ptX, ptY, prevX, prevY, 'black', 2);
        }

        if (type == renderType.points) {
            var radgrad = ctx.createRadialGradient(ptX, ptY, 8, ptX - 5, ptY - 5, 0);
            radgrad.addColorStop(0, 'Green');
            radgrad.addColorStop(0.9, 'White');
            ctx.beginPath();
            ctx.fillStyle = radgrad;
            //Render circle
            ctx.arc(ptX, ptY, 8, 0, 2 * Math.PI, false)
            ctx.fill();
            ctx.lineWidth = 1;
            ctx.strokeStyle = '#000';
            ctx.stroke();
            ctx.closePath();
        }

        prevX = ptX;
        prevY = ptY;
    }
}

 

Once the data points are rendered the chart looks like the following:

 

Conclusion

You can see that there’s a fair amount of JavaScript code required to use the canvas object. However, once the different API functions are understood it’s simply a process of calling the appropriate functions to render lines, text or shapes. Although the CanvasChart object shown here is only a prototype at this point, I hope it provides insight into what the HTML 5 canvas is capable of rendering and how some of the features it provides can be used.

Download Canvas Demo

Use jQuery to extract data from HTML lists and tables

A question that I’ve been seeing more frequently these days is how to extract a JavaScript object from an HTML list or table, given no data or information other than the markup. It’s not ideal to work backwards from HTML, but sometimes you just don’t have a lot of choice in the matter.

Whether you’re enhancing legacy elements that have been generated on the server-side or want to parse the output of a third-party DHTML widget, there are a variety of situations where converting HTML to raw data is a legitimate need. You may have seen iterative solutions to this problem before. However, nested looping code gets messy fast, doesn’t feel much like idiomatic jQuery, and certainly isn’t as concise as you’d probably like.

Luckily, one of JavaScript’s lesser-known utility methods and jQuery’s implementation of it can improve the situation quite a bit. In this post, I’m going to show you how to use this method, jQuery’s cross-browser solution, and how to use it to extract data objects from arbitrary HTML lists and tables.

Array.map()

It turns out that there’s a tool perfectly suited to the task of coercing one data structure into another: map.

Map is a higher-order function that allows you to transform the contents of a collection by applying a function to each item, capturing the result, and building a new collection of those results.

Map is a perfect tool for translating a collection full of extraneous data into a tightly-focused collection of exactly the desired subset. Even better, JavaScript 1.6 even includes a native implementation of map, which is exposed as a method on the Array prototype.

For example, this is how you could use JavaScript 1.6?s Array.map() to analyze an array of strings and create a new array containing each string’s length:

var sites = ['Encosia', 'jQuery', 'ASP.NET', 'StackOverflow'];
 
// For each site in the array, apply this function 
//  and build an array of the results.
var lengths = sites.map(function(site, index) {
  // Use the length of each name as its value in the new array.
  return site.length;
});
 
// This outputs: [7, 6, 7, 13]
console.log(lengths);

This is a very simple example, but you can probably already imagine applying that same technique to an array of list elements or table rows. The concise expressiveness of the map approach is great for paring away extraneous markup and extracting just underlying data.

Mapping uncharted territory

Unfortunately, JavaScript 1.6 and its map implementation is not something that you can count on being available in older browsers. Notably, Internet Explorer doesn’t provide an Array.map() implementation until IE9.

Though that is disappointing, map isn’t difficult to manually implement. For example, this is a polyfill that the MDC recommends for patching Array.map() into older browsers:

if (!Array.prototype.map) {
  Array.prototype.map = function(fun /*, thisp */)  {
    "use strict";
 
    if (this === void 0 || this === null)
      throw new TypeError();
 
    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== "function")
      throw new TypeError();
 
    var res = new Array(len);
    var thisp = arguments[1];
    for (var i = 0; i < len; i++)  {
      if (i in t)
        res[i] = fun.call(thisp, t[i], i, t);
    }
 
    return res;
  };
}

That’s a workable solution, but I doubt you’re very excited about the prospect of including all this code in your page. I know I wouldn’t be.

jQuery has you covered

If you’re already including jQuery in your pages, the good news is that jQuery has a built-in map implementation that works in every browser. In fact, jQuery provides two separate map methods: one that’s specially suited to working with jQuery selections and a general utility method that’s more similar to the polyfill shown above.

For working with HTML, I’m going to focus on using the former: .map().

To replicate the JavaScript 1.6 dependent example shown earlier, using jQuery’s implementation instead, the code would look like this:

var sites = ['Encosia', 'jQuery', 'ASP.NET', 'StackOverflow'];
 
// Same as before, using jQuery's map() implementation.
var lengths = $(sites).map(function(index, site) {
  // Use the length of each site name as its value in the new array.
  return site.length;
});
 
// This outputs: [7, 6, 7, 13]
console.log(lengths);

Making “this” approach more concise

To condense the code a bit, we can take advantage of the execution context within the callback function. During each callback, this holds the value of the array item currently being operated on. So, there’s no need to bother capturing the callback’s two input parameters:

var lengths = $(sites).map(function() {
  // "this" refers to the current array element as this callback is
  //  applied to each array element.
  return this.length;
});

That isn’t a huge improvement, but every little bit helps and I’ll be using this in the examples throughout the rest of this post. So, I wanted to make sure what’s happening there is clear.

Unwrapping the result of jQuery’s .map()

The one quirk when using jQuery’s .map() method is that it sometimes returns a jQuery wrapped set; specifically, when you apply it to the result of a jQuery DOM selection. Even if your mapping function returns scalar values like strings and numbers, the end result of .map() will include the jQuery object prototype on each element.

That isn’t really a problem if you only intend to use that result immediately in your JavaScript code. However, the jQuery object prototype hanging off each element throws a wrench in the works if you try to use JSON.stringify() on the result of .map(). Since JSON serialization is such a common task when storing or transmitting JavaScript data, this quirk turns out to be a real issue.

The solution is to call jQuery’s get() method on those wrapped-array results, which boils them down to plain arrays. When you see .get() tagged onto the end of the examples ahead, that’s why it’s there.

Now, let’s take a look at applying .map() to HTML and using it to extract data.

Mapping the data within HTML unordered lists

Using .map() against an unordered list is one of the most straightforward examples to start with. Imagine you had this simple HTML markup:

<ul>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
</ul>

To extract each of those items’ displayed value, you could use .map() like this:

// Returns ['Item 1', 'Item 2', 'Item 3']
$('li').map(function() {
  // For each <li> in the list, return its inner text and let .map()
  //  build an array of those values.
  return $(this).text();
}).get();

Complicating things slightly, maybe the list items also have an HTML5 data- attribute that you need to collect in addition to their values:

<ul>
  <li data-id="123">Item 1</li>
  <li data-id="456">Item 2</li>
  <li data-id="789">Item 3</li>
</ul>

Using .map() to extract that more complex data is just as easy:

// Returns [{id: 123, text: 'Item 1'}, 
//          {id: 456, text: 'Item 2'},
//          {id: 789, text: 'Item 3'}]
$('li').map(function() {
  // $(this) is used more than once; cache it for performance.
  var $item = $(this);
 
  return {
    // Note: using .data() to read HTML5 data- attributes 
    //  requires jQuery 1.4.3+. Use attr() in older versions.
    id: $item.data('id'),
    text: $item.text()
  };
}).get();

As you can see, .map() is a powerful tool for concisely pulling arbitrary bits of data together into a useful structure. You could certainly do this with a temp variable and for-loop, but it’s hard to beat the clean expressiveness this approach lends your code.

There’s a great JavaScript learning opportunity in the code above, but it’s on a bit of a tangent. Rather than let this post run even longer, I wrote about that in a separate post. If you’re interested in how an innocuous change to the location of one curly brace in the preceding code can transparently break it, that post is for you.

You can find that post here: In JavaScript, curly brace placement matters: An example.

Extracting data from HTML tables

Working with the lists is good for a simple example, but what if we need to apply this technique to an HTML structure that’s more complex than an unordered list?

HTML tables are one of the most common targets for this technique. It’s not unusual to end up with a pre-rendered table that was generated off-page and to desire a client-side data structure representing that table’s data.

For example, here’s a tabular representation of the same data contained in the second list example:

<table id="myTable">
  <thead>
    <tr>
      <th>id</th>
      <th>text</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>123</td>
      <td>Item 1</td>
    </tr>
    <tr>
      <td>456</td>
      <td>Item 2</td>
    </tr>
    <tr>
      <td>789</td>
      <td>Item 3</td>
    </tr>
  </tbody>
</table>

If you wanted to boil that table down to exactly the same JavaScript object shown in the second list example, this .map() usage would do the trick:

// Returns [{id: 123, text: 'Item 1'}, 
//          {id: 456, text: 'Item 2'},
//          {id: 789, text: 'Item 3'}]
$('#myTable tbody tr').map(function() {
  // $(this) is used more than once; cache it for performance.
  var $row = $(this);
 
  // For each row that's "mapped", return an object that
  //  describes the first and second <td> in the row.
  return {
    id: $row.find(':nth-child(1)').text(),
    text: $row.find(':nth-child(2)').text()
  };
}).get();

The key to making this approach work is using the :nth-child selector to index into each row and retrieve the contents of the cells we’re interested in. This is very similar to how we handled the unordered list earlier, but can be applied to arbitrarily large structures such as wide HTML tables.

If you use this approach, one thing to keep in mind is that :nth-child uses one-based indexing. So, you must use :nth-child(1) to select the first cell, not :nth-child(0) as you might expect.

A general solution for tables

Using hard coded :nth-child selectors works well enough in simple scenarios, but it’s brittle. If the table structure changes, relying on a certain table layout will break. Hard coding the selectors for each column also becomes tedious when dealing with wider tables that have many columns.

So, as you apply this technique to larger or less predictable tables, you may desire a more general solution for extracting the data. One way of doing that is using the table’s column heading cells to build a basic schema of the table’s data.

Assuming your table has a proper <thead>, this is how you could extract an array of its column headings to use as a schema for mapping the rest of the table’s data:

var columns = $('#myTable thead th').map(function() {
  // This assumes that your headings are suitable to be used as
  //  JavaScript object keys. If the headings contain characters 
  //  that would be invalid, such as spaces or dashes, you should
  //  use a regex here to strip those characters out.
  return $(this).text();
});

With that column list handy, we can determine which column name any cell in the table should be filed under, given nothing more than its index in the row. Now we can automate the process that previously required those :nth-child selectors:

var tableObject = $('#myTable tbody tr').map(function(i) {
  var row = {};
 
  // Find all of the table cells on this row.
  $(this).find('td').each(function(i) {
    // Determine the cell's column name by comparing its index
    //  within the row with the columns list we built previously.
    var rowName = columns[i];
 
    // Add a new property to the row object, using this cell's
    //  column name as the key and the cell's text as the value.
    row[rowName] = $(this).text();
  });
 
  // Finally, return the row's object representation, to be included
  //  in the array that $.map() ultimately returns.
  return row;
 
// Don't forget .get() to convert the jQuery set to a regular array.
}).get();

That’s it.

With all the comments, that looks like more work than it actually is. Eleven lines of code for the entire ordeal isn’t bad considering that it will automatically handle the majority of tables you throw at it.

Conclusion

I’m going to stop here, before this gets any longer. I hope that you found this helpful and/or interesting.

Even if you don’t often convert HTML markup to JavaScript objects, do keep .map() in mind when you’re working with collections of any type. When you need it, the notion of map is an extremely useful aspect of JavaScript’s functional nature, but often goes overlooked.

Related posts:

  1. Use jQuery and quickSearch to interactively search any data
  2. How to easily enhance your existing tables with simple CSS
  3. In JavaScript, curly brace placement matters: An example

You’ve been reading Use jQuery to extract data from HTML lists and tables, originally posted at Encosia. I hope you enjoyed it, and thanks for reading.

If you’ve got any feedback, please click through and leave a comment; I’d love to hear from you. You can click here to jump directly to the comment section of this post.

Google Wave Gadgets Get a Second Life as Google Shared Spaces [Collaboration]

One of the neatest features in the discontinued-but-alive Google Wave was its collection of gadgets and extensions. Many of those gadgets live on in Google’s new Shared Spaces, where you can invite others to contribute, vote, and collaborate on the web. More »







jQuery Templates, composite rendering, and remote loading

In my last post about jQuery Templates, I showed you how to use template composition to build a template out of simple sub-templates. These composite templates are a great way to address the complexity that creeps into real-world UIs, as they inevitably grow and become more intricate. However, one feature missing from my last example was the ability to store those composite templates in external files and load them asynchronously for rendering.

I’ve described how to accomplish that with single templates in the past, using jQuery’s AJAX utilities and a particular usage of tmpl(). Unfortunately, remotely loading a group of composite templates from a single file is not quite as simple, and the technique I’ve described previously will not work.

Not to worry though, it’s still relatively easy.

In this post, I’ll show you how to move a group of composite templates to an external file, how to load and render them with jQuery Templates, and how to take advantage of an expected benefit to improve separation of concerns.

Caution: If you haven’t read my previous posts about remotely loading jQuery Templates definitions and using {{tmpl}} to achieve template composition, read them before continuing with this post. I’m not going to cover that material again here, and this may not make much sense without those prerequisites.

Moving the templates to an external file

Breaking the invoice template apart helped make it more approachable and maintainable, but I don’t like leaving the template embedded in the page’s markup. The larger a single file becomes, the more difficult it is to understand and work with – especially over time.

Disentangling chunks of the presentation tier and moving them to separate files is a great way to attack the problem of bloated pages and views. We’ve been doing that since the beginning of the web, from seemingly-ancient techniques like SSI includes, to file includes in scripting frameworks like ASP and PHP, to partial views in MVC frameworks. So, why stop now just because the templates are rendered in the browser?

Moving the previous example’s template definitions to a separate file is as simple as it sounds. Just take the invoice template and both its row templates, script wrappers included, and move them into a new file of your choosing. I’m going to move them to a file named _invoice.tmpl.htm:

<!-- Tip: It's safe to use HTML comments in the file -->
 
<!-- Invoice container template -->
<script id="invoiceTemplate" type="x-jquery-tmpl">
  <table class="invoice">
  {{each lineItems}}
    {{tmpl($value) get_invoiceRowTemplateName(type)}}
  {{/each}}
  </table>
</script>
 
<!-- Invoice row templates -->
<script id="serviceRowTemplate" type="x-jquery-tmpl">
  <tr class="service">
    <td colspan="2">${service}</td>
    <td colspan="2">${price}</td>
  </tr>
</script>
 
<script id="itemRowTemplate" type="x-jquery-tmpl">
  <tr class="item">
    <td>${item}</td>
    <td>${description}</td>
    <td>${price}</td>
    <td>${qty}</td>
  </tr>
</script>

Naming the template file

If you’re wondering why I chose that somewhat convoluted filename for the template, I’ll explain:

Ideally, I would like to call the template something like invoiceTemplate.tmpl, but most popular web servers refuse to serve files with non-standard extensions by default. You can circumvent that with a bit of manual configuration, but it’s not worth the unending hassle of extra configuration work on every server and/or site where you use this technique. So, .tmpl is out.

I really liked Nathan Smith’s suggestion for a naming compromise on my previous post about remote loading, which boils down to this:

  • Prefix the filename with an underscore. This denotes a partial view in many modern view engines and is a useful convention for indicating that the file is not a valid/complete HTML document.
  • Nathan suggested following _templateName with .tpl, to indicate that it’s a template. I’m going to tweak that slightly and use .tmpl, so it’s more clear that the template is intended for use with jQuery Templates.
  • The file should end in .htm, to be sure the file will be readily served up under almost any web server’s default configuration. Using .htm or another text/html extension also improves the odds that the template definitions will be served with appropriate compression and caching.

The first two are just suggestions, of course. You can use any arbitrary naming scheme you prefer and the approach described in this post will still work fine.

I do recommend sticking with an .htm or .html extension though. I (stubbornly) went through the configuration hassle of using .tpl when I was originally working with jTemplates’ remote loading feature a couple years ago, and eventually had to give up on it. The ongoing configuration hassles ultimately outweighed the benefit of a uniquely descriptive extension.

Loading and rendering the template

With the templates moved to an external file, we need a way to load and render them. As I mentioned earlier, the approach I’ve previously described for remote template loading isn’t viable in this scenario. Treating the external file as a simple template string only works if the file contains a single template definition and no extraneous markup. Our file fails on both counts.

Another disadvantage my previous approach is caching. When you render a string-based template, jQuery Templates doesn’t cache the compiled template. If you end up rendering the same template more than once per pageview, the string-based approach was slower than it could have been.

To solve both those issues, we can use jQuery to load the contents of the template file, inject all of it into the document, and then work with the templates as if they had been embedded in the page all along.

// The invoice object to render (see previous post).
var invoice = {
  invoiceItems: [
    { type: 'item',
      part: '99Designs', description: '99 Designs Logo',
      price: 450.00, qty: 1 },
    { type: 'service',
      service: 'Web development and testing',
      price: 25000.00 },
    { type: 'item',
      part: 'LinodeMonthly', description: 'Monthly site hosting',
      price: 40.00, qty: 12 }
  ]
};
 
// Asynchronously load the template definition file.
$.get('_invoice.tmpl.htm', function(templates) {
  // Inject all those templates at the end of the document.
  $('body').append(templates);
 
  // Select the newly injected invoiceTemplate and use it
  //  render the invoice data.
  $('#invoiceTemplate').tmpl(invoice).appendTo('body');
});

Injecting the template definitions into the page’s markup allows you to render them with the same $('#templateId').tmpl(data) syntax that you’ve seen in most jQuery Templates examples.

Bringing the row template resolver along for the ride

One remaining annoyance is the now-orphaned row template name resolver, get_invoiceRowTemplateName() (covered in my composite template post). Keeping that function with the rest of the page’s JavaScript does work, but I’m not happy with it. To get the full benefit of encapsulating the template in an external file, we should keep any dependent JavaScript code with the template itself.

That’s especially true if the template is used from more than one page.

As it turns out, accomplishing that is much easier than it may seem at first. All we need to do is move the resolver function right into _invoice.tmpl.htm:

<!-- Invoice container template -->
<script id="invoiceTemplate" type="x-jquery-tmpl">
  <table class="invoice">
  {{each lineItems}}
    {{tmpl($value) get_invoiceRowTemplateName(type)}}
  {{/each}}
  </table>
</script>
 
<!-- Invoice row templates -->
<script id="serviceRowTemplate" type="x-jquery-tmpl">
  <tr class="service">
    <td colspan="2">${service}</td>
    <td colspan="2">${price}</td>
  </tr>
</script>
 
<script id="itemRowTemplate" type="x-jquery-tmpl">
  <tr class="item">
    <td>${item}</td>
    <td>${description}</td>
    <td>${price}</td>
    <td>${qty}</td>
  </tr>
</script>
 
<!-- This function is used by the invoice container to determine -->
<!--  which row template to render for a given line item -->
<script type="text/javascript">
  function get_invoiceRowTemplateName(type) {
    // Return a template selector that matches our
    //  convention of <type>RowTemplate.
    return '#' + type + 'RowTemplate';
  }
</script>

When you inject markup into the DOM, browsers will immediately parse and evaluate that markup just as they do during the initial page load – including any JavaScript code in the markup. Since browsers do this in the same single-thread that they execute JavaScript, it’s safe to assume that embedded functions are available immediately after the markup has been injected.

It seems almost too good to be true, like one of those handy techniques that works in every browser except some version of IE. However, embedding the supporting function inside the template file works in every browser I’ve tested, even including the full complement of JavaScript-enabled options on BrowserShots.org.

Conclusion

I’ve been using this exact technique in production for about a month now. I initially came up with several approaches, but wanted to try them in real-world code before I recommended one. I’m happy to report that this has been working great for me so far. I hope you’ll find it helpful too.

One caveat is that you should be careful about loading and injecting the external template more than once. Injecting multiple copies of the template definitions over and over actually doesn’t break the rendering process in browsers I’ve tested, but it will unecessarily impact performance as the DOM grows larger with every new injection.

I’m going to cover that and another templating concurrency issue soon, but if you want a head start: test $.template('#templateName') to determine whether a particular template is already loaded and cached.


You’ve been reading jQuery Templates, composite rendering, and remote loading, originally posted at Encosia. I hope you enjoyed it, and thanks for reading.

Related posts:

  1. Using external templates with jQuery Templates
  2. Composition with jQuery Templates: Why and How
  3. A few thoughts on jQuery templating with jQuery.tmpl

Shortcut Manager Is a Powerful Custom Shortcut Builder for Chrome [Downloads]

Chrome: If you’ve ever been annoyed you couldn’t find an extension that had the perfect shortcut for the task you wanted, Shortcut Manager is the tool for you; build custom shortcuts that access browser functions and even call JavaScript. More »







Using external templates with jQuery Templates

Now that jQuery Templates is official and definitely will not include remote template loading, I wanted to publish a quick guide on implementing that yourself. As I mentioned previously, there’s a handy interaction between jQuery Templates’ API and jQuery’s AJAX methods that makes this easier than you might expect.

In this post, I’ll show you how to use a plain string as a template, how to asynchronously load an external template file as a string, and how to render it with jQuery Templates once it’s loaded.

Defining an external template

Defining a template suitable for remote loading requires almost no extra effort. Simply create a new file and fill it with the same sort of jQuery Templates fragment that you might normally embed in a text/html <script> element.

For example, given this person object:

var person = { name: 'Dave' };

You might define this template for that data in a file called PersonTemplate.htm:

<p>Hello, ${name}.</p>

Be sure not to wrap the template in a <script> element. Since we’ll be loading it remotely, that obscuring measure isn’t necessary. Also be sure not to include any of the HTML boilerplate that may come along with creating a new HTML file in your editor of choice, like <html> or <body>.

An added bonus that comes along with dropping the <script> container is that you get more reliable syntax highlighting for the template’s markup. Most editors don’t provide HTML syntax highlighting within <script> elements, even when their type is text/html, but work fine in the external files.

Using strings as templates

Though most jQuery Templates examples revolve around referencing template definitions hidden inside <script> elements, it’s also possible to provide the template as a plain string. Using the $.tmpl(template, data) syntax, a simple string version of the template may be provided as that first parameter.

For example, these are both perfectly valid ways to render a template, using the person object from the previous section:

// Specifying the template inline.
$.tmpl('<p>Hello, ${name}.</p>', person);
 
// Assign that same template to a JavaScript variable, and then
//  use that string value as a template parameter to $.tmpl().
var salutationTmpl = '<p>Hello, ${name}.</p>';
 
$.tmpl(salutationTmpl, person);

With that ability to use a string as a template, we just need a way to get the external template file’s content loaded into a string variable.

Loading the external template

With that in mind, probably the easiest way to load an external template is to use jQuery’s $.get() method. When you target $.get() at a static HTML file, the result passed to its callback is a string containing the file’s content. Exactly what we’re after.

For example, if an external template were stored in a file named PersonTemplate.htm, this is how you could use $.get() to load and render that external template with jQuery Templates:

// Asynchronously our PersonTemplate's content.
$.get('PersonTemplate.htm', function(template) {
 
  // Use that stringified template with $.tmpl() and 
  //  inject the rendered result into the body.
  $.tmpl(template, person).appendTo('body');
});

That’s it.

Because you have to get involved with more of the moving parts, this is slightly more complex than jTemplates’ processTemplateURL, but it’s very manageable.

Caveats

Compilation caching – When you use this method, it’s important to keep in mind that jQuery Templates will not automatically cache the compiled template. If you intend to reuse the same template many times during a given pageview, this approach is slower than the embedded <script> technique.

It’s possible to work around that drawback by using $.template() to compile the remotely loaded template and store it manually, but I’m omitting that here to keep things simple.

If you’re interested, I’ll cover that in follow up post.

HTTP caching – In production, you should ensure that your server’s caching configuration is correct. If your server sends a proper expires header, requesting the same template multiple times during the lifespan of a page will only cause the browser to make one HTTP request. Even subsequent HTTP requests to check for a 304 status aren’t necessary if a future expires header is set on the response.

Template file naming – I recommend using a standard filename extension for your external template files, like .htm or .txt. I started out using more descriptive extensions like .tpl, but server configuration was a constant hassle. Important things like HTTP compression, expires headers, and even serving the files at all are common issues when using nonstandard extensions.


You’ve been reading Using external templates with jQuery Templates, originally posted at Encosia. I hope you enjoyed it, and thanks for reading.

Related posts:

  1. A few thoughts on jQuery templating with jQuery.tmpl
  2. Use jQuery and ASP.NET AJAX to build a client side Repeater
  3. How you can force the Ajax Script Loader to use jQuery 1.4

Inline AJAX DropDown and Text Editing with Asp.Net MVC and jQuery

including how to use a database to populate the dropdown


First thing is first, you will need to download
jQuery
and the
Jeditable
plugin (I prefer to refer to it as the Jedi-Table!).
Be sure to put these references in your View (or Masterpage).
Next, you have to set up a view on which to use an inline edit.
I find that I often want to use this approach on tables of information.
For this View, I will set it to use an IEnumerable of an Item I have called ‘ItemOwner’ (this is arbitrary and does not really matter).
It will be a simple table that lists the Name and the Country of the owner, both of which will be editable inline.
Here is the Index in my ExampleController.cs:

myDataContext db = new myDataContext();
public ActionResult Index()
{
    // get the info for the 'Countries' dropdown:
    ViewData["countries"] = db.Countries
        .Select(x => new SelectListItem()
        {
            Text = x.Name,
            Value = x.Id.ToString()
        }).ToJson();

    // get the 'ItemOwners' I am interested in:
    var owners = db.ItemOwners.Take(3);

    return View(owners);
}

As you can see there, I am also pulling the countries from the database and throwing them into the ViewState – we will get to this later.
Since the Country is actually a foreign key relation, the value is set to an integer which is the identity field in the database.
It is also using a .ToJson() extension which takes a IEnumerable<SelectListItem> and
puts it into a simple JSON string that I use which is here:

public static string
    ToJson(this IEnumerable<SelectListItem> slis)
{
    string output = "{";
    if (slis != null)
    {
        for (int i = 0; i < slis.Count(); i++)
        {
            output += " '" + slis.Skip(i)
            .First().Value + "': '" +
            slis.Skip(i).First().Text + "'" +
            (i == slis.Count() - 1 ? " " : ",");
        }
    }
    return output += "}";
}

There is probably a better way to do that… but I don’t know it?!

I am also pulling 3 ItemOwners from the database, I know this is silly, but it just an example.
Here is how I am displaying them in the view:

<table>
    <thead>
        <tr>
            <th>Name</th>
            <th>Country</th>
        </tr>
    </thead>
    <tbody>
        <% foreach(var owner in Model) { %>
        <tr>
            <td><%= owner.Name %></td>
            <td><%= owner.Country.Abbreviation %></td>
        </tr>
        <% } %>
    </tbody>
</table>

Now that there is a simple table we want to make it a bit more interactive.
Since we aregoing to make all of these fields editable, we need to add in a way to distinguish exactly what they are.
To do that, we will need two things: the id of the item they are editing, and the type of inline editing we will be doing (i.e. dropdown or text input).
So to do that, let’s add in a few css classes and an identifieng ID:

<td id="name<%= owner.Id %>" class="editable text">
    <%= owner.Name %></td>
<td id="ctry<%= owner.Id %>" class="editable dropdown">
    <%= owner.Country.Abbreviation %></td>


And now add a little css to make them appear to be clickable:

td.editable:hover
{ cursor:pointer; background-color:Orange; }

Now they all look like you can click on them, so we can move on to making the click actually do something.



This is where the jQuery comes in, and it is very simple.
I have made these ‘helper’ methods in Javascript to make all of my inline calls centrally controllable, I keep this in my sites script folder so if I change one inline edit, I change them all; it also makes for more readable Javascript on each page.

function InlineDropdown(collectionToDropDown, ajaxAddress, dropDownDataSet) {
    collectionToDropDown.editable(ajaxAddress,
    {
        data: dropDownDataSet,
        type: 'select',
        indicator: 'saving...',
        tooltip: 'click to edit...',
        submit: 'Save',
        style: 'inherit',
        placeholder: 'click to edit'
    });
}

function InlineTextbox(collectionToInline, ajaxAddress) {
    collectionToInline.editable(ajaxAddress,
    {
        indicator: 'saving...',
        tooltip: 'click to edit...',
        style: 'inherit',
        placeholder: 'click to edit'
    });
}

function InlineTextarea(collectionToInline, ajaxAddress) {
    collectionToInline.editable(ajaxAddress,
    {
        type        : 'textarea',
        rows        : 4,
        indicator   : 'saving...',
        tooltip     : 'click to edit...',
        style       : 'inherit',
        submit      : 'Save',
        onblur      : 'ignore',
        placeholder : 'click to edit'
    });
}

Obviously you can read all about the options on the Jeditable
page, but this is how I set them.
Also notice I have a InineTextarea included as well for a textarea which is not covered here but works the exact same.

Now the jQuery calls are almost trivial:

InlineTextbox(
    $('td.editable.text'),
    "<%= Url.Content("~/Ajax/ItemOwner.ashx") %>"
);

InlineDropdown(
    $('td.editable.dropdown'),
    "<%= Url.Content("~/Ajax/ItemOwner.ashx") %>",
    <%= ViewData["countries"].ToString() %>
);

What that is doing is sending the POST requests to the specified address.
The POST contains a few things:

  • id – the id of the element that sent the request
  • value – the new value passed by the element

We are also passing more information there – remember that we passed both the type of field to edit and the id of the ItemOwner to edit, ie [name837] which emans we want to edit the Name field of ItemOwner 837.
So we simply set up an ashx handler (which we specified above) to do the dirty work:

public void ProcessRequest(HttpContext context)
{
    string newValue;
    try
    {
        myDataContext db = new myDataContext();
        string elementId = context.Request.Form["id"];

        // since we made the first 4 of the id the 'field' whic to edit
        // we can just pull the first 4 letters for use in our switch:
        string fieldToEdit = elementId.Substring(0, 4);

        //now take anything after those 4 and it is the Id:
        int idToEdit = Convert.ToInt32(elementId.Remove(0, 4));

        // the value is simply a string:
        newValue = context.Request.Form["value"].Trim();

        // now that we have the id, get the ItemOwner from the db
        ItemOwner owner = db.ItemOwners.FirstOrDefault(x => x.Id == idToEdit);

        // after all is said and done, we will return newValue to the user so the field
        // looks as if the change has taken place (which it has)

        // using the field we pulled above, decide what to do:
        switch (fieldToEdit)
        {
            // name is easy
            case "name": owner.Name = newValue; break;

            // since the country is an integer foreign key, we need to Convert.ToInt32:
            case "ctry":
                owner.CountryId = Convert.ToInt32(newValue);
                // now that we have recorded the value, we want to return the text to
                // the user and not the id value which would make no sense
                newValue = db.Countries.FirstOrDefault(x => x.Id == owner.CountryId).Abbreviation;
                break;
            // if it wasn't caught, something is wrong:
            default: throw new Exception("invalid fieldToEdit passed");
        }

        db.SubmitChanges(); // save it
    }
    // now if an exceptions were reported, the user can see what happened
    // this also inform the user nothing was saved
    // you could easily make this not reported to the user and logged elsewhere
    catch (Exception ex)
    { newValue = "Error: " + ex.Message + " [nothing written to db]"; }

    //now return what you want in the element:
    context.Response.Write(newValue);
}

And that is all it takes.

Keep Your Gmail Tasks, Chat, and Compositions Open in New Chrome Windows [Gmail Tip]

Chrome only: Up until now, closing the main Gmail or Google Apps mail tab in your browser would close down any connected windows you had open, too—compose windows, Gmail tasks, popped-out chats, and the like. Now Gmail's fixed that with a JavaScript tweak for Chrome, so you can keep working on the email, or keep a conversation running, after you’ve closed down your main inbox. [Official Gmail Blog] More »









TasksGoogleSearchingSearch EnginesGoogle Calendar

Learn to Make Your Own Chrome Extensions [Programming]

Lifehacker readers are often interested in learning how to code, and if you’re a Chrome user, development blog Tutorialzine has a great tutorial to start you off making simple Chrome extensions. More »









Google ChromeBrowsersClientsWWWFAQs Help and Tutorials

WP Like Button Plugin by Free WordPress Templates