2

I am trying to sort the following static HTML product listing based on the div that contains the price. In this case the divs all have a class of price-bold. Is there a way to sort the list of products using javascript to sort lowest to highest and highest to lowest with a button/text on-click command? Your help and expertise is greatly appreciated. Thank you, Dan

<div id="gallerypaginate2" class="paginationstyle"></div>
<div id="contents">
    <table width="100%" class="vertical" id="contents-table">
        <tr class="pagination-row">
            <td width="25%" class="horizontal-seperator vertical-seperator">
                <a href="mica136-3s.html"><img src="http://ep.yimg.com/ca/I/yhst-129288146819219_2148_2126916" width="125" height="71" border="0" hspace="0" vspace="0" alt="3-Shade Billiard Light - Oversized" title="3-Shade Billiard Light - Oversized" /></a>
                <div class="name"><a href="mica136-3s.html" title="3-Shade Billiard Light - Oversized">3-Shade Billiard Light - Oversized</a></div>
                <div class="price-bold">$2,088.00</div>
            </td>
            <td width="25%" class="horizontal-seperator vertical-seperator">
                <a href="micaf101-01-abbey.html"><img src="http://ep.yimg.com/ca/I/yhst-129288146819219_2148_2132333" width="125" height="118" border="0" hspace="0" vspace="0" alt="Abbey Craftsman Fan and Mica Light Kit" title="Abbey Craftsman Fan and Mica Light Kit" /></a>
                <div class="name"><a href="micaf101-01-abbey.html" title="Abbey Craftsman Fan and Mica Light Kit">Abbey Craftsman Fan and Mica Light Kit</a></div>
                <div class="price-bold">$711.00</div>
            </td>
            <td width="25%" class="horizontal-seperator vertical-seperator">
                <a href="mica007.html"><img src="http://ep.yimg.com/ca/I/yhst-129288146819219_2148_2150148" width="103" height="125" border="0" hspace="0" vspace="0" alt="Beanpot Table Lamp" title="Beanpot Table Lamp" /></a>
                <div class="name"><a href="mica007.html" title="Beanpot Table Lamp">Beanpot Table Lamp</a></div>
                <div class="price-bold">$442.00</div>
            </td>
            <td width="25%" class="horizontal-seperator">
                <a href="mica012.html"><img src="http://ep.yimg.com/ca/I/yhst-129288146819219_2148_2162401" width="125" height="71" border="0" hspace="0" vspace="0" alt="Buffet Table Lamp" title="Buffet Table Lamp" /></a>
                <div class="name"><a href="mica012.html" title="Buffet Table Lamp">Buffet Table Lamp</a></div>
                <div class="price-bold">$370.00</div>
            </td>
        </tr>
        <tr class="pagination-row">
            <td width="25%" class="horizontal-seperator vertical-seperator">
                <a href="mica051.html"><img src="http://ep.yimg.com/ca/I/yhst-129288146819219_2148_2169261" width="125" height="71" border="0" hspace="0" vspace="0" alt="Bungalow Floor Lamp" title="Bungalow Floor Lamp" /></a>
                <div class="name"><a href="mica051.html" title="Bungalow Floor Lamp">Bungalow Floor Lamp</a></div>
                <div class="price-bold">$1,370.00</div>
            </td>
            <td width="25%" class="horizontal-seperator vertical-seperator">
                <a href="mica119c.html"><img src="http://ep.yimg.com/ca/I/yhst-129288146819219_2148_2177066" width="125" height="71" border="0" hspace="0" vspace="0" alt="Carmel Wall Sconce" title="Carmel Wall Sconce" /></a>
                <div class="name"><a href="mica119c.html" title="Carmel Wall Sconce">Carmel Wall Sconce</a></div>
                <div class="price-bold">$505.00</div>
            </td>
            <td width="25%" class="horizontal-seperator vertical-seperator">
                <a href="micaf101-bw.html"><img src="http://ep.yimg.com/ca/I/yhst-129288146819219_2148_2182877" width="125" height="71" border="0" hspace="0" vspace="0" alt="Ceiling Fan with Bell White Light Kit" title="Ceiling Fan with Bell White Light Kit" /></a>
                <div class="name"><a href="micaf101-bw.html" title="Ceiling Fan with Bell White Light Kit">Ceiling Fan with Bell White Light Kit</a></div>
                <div class="price-bold">$524.00</div>
            </td>
            <td width="25%" class="horizontal-seperator">
                <a href="micaf101-c.html"><img src="http://ep.yimg.com/ca/I/yhst-129288146819219_2148_2192940" width="125" height="71" border="0" hspace="0" vspace="0" alt="Ceiling Fan with Coppersmith Mica Light Kit" title="Ceiling Fan with Coppersmith Mica Light Kit" /></a>
                <div class="name"><a href="micaf101-c.html" title="Ceiling Fan with Coppersmith Mica Light Kit">Ceiling Fan with Coppersmith Mica Light Kit</a></div>
                <div class="price-bold">$695.00</div>
            </td>
        </tr></table>
</div>
<div id="gallerypaginate" class="paginationstyle"><a href="#" rel="previous">Prev</a> <span class="flatview"></span> <a href="#" rel="next">Next</a></div>

2 Answers 2

6

Knowing that the length of my solution would probably scare you off, I decided to make a pure JS solution as a challenge.

Here it is, in all of its weighty glory:

addListeners();

function addListeners()
{
    var toggle = toggleTableSort;
    var node = document.getElementById("sortTables");
    node.onclick = toggle();
}

function toggleTableSort()
{
    var status = 0;
    return function()
    {
        var table = getTable();
        var tableData = table['data'];
        var rows = table['rows'];
        if(status === 0)
        {
            status = 1;
            sortTableData(tableData, rows, "descending");
        }else if(status === 1)
        {
            status = 0;
            sortTableData(tableData, rows, "ascending");  
        }
    }   
}

function getTable()
{
    var container = document.getElementById("contents-table");
    var tbody =  getElementNodes(container, "TBODY", 1, {})[0];
    var rows = getElementNodes(tbody, "TR", 0, {"class": "pagination-row"});
    var tableData = grabTableData(rows);
    return {"data": tableData, "rows": rows};   
}

function getElementNodes(parent, tag, num, attributes)
{
    var nodes = parent.childNodes;
    var temp = [];
    tag = tag.toUpperCase();
    if(num === 0)
    {
        num = nodes.length;   
    }
    for(var i=0;i<nodes.length;i++)
    {
        var node = nodes[i];
        if(temp.length <= num)
        {
            if(node.nodeType === 1 && node.tagName === tag)
            {
                var attributeCheck = true;
                for(var attribute in attributes)
                {
                    if(attributes.hasOwnProperty(attribute))
                    {
                        var newAttribute;
                        if(attribute === "class" && !node.getAttribute(attribute))
                        {
                            newAttribute = "className";   
                        }
                        if(newAttribute)
                        {
                            if(node.getAttribute(newAttribute) !== attributes[attribute])
                            {
                                attributeCheck = false;
                                break;
                            }
                        }else if(!newAttribute)
                        {
                            if(node.getAttribute(attribute) !== attributes[attribute])
                            {
                                attributeCheck = false;
                                break;
                            }
                        }
                    }
                }
                if(attributeCheck)
                {
                    temp.push(node);   
                }
            }
        }else if(temp.length > num)
        {
            break;   
        }
    }
    return temp;
}

function grabTableData(rows)
{
    var data = [];
    for(var i=0;i<rows.length;i++)
    {
        var row = rows[i];
        var tableData = getElementNodes(row, "TD", 0, {"width": "25%"});
        data = data.concat(tableData);
    }
    return data;
}

function sortTableData(tableData, rows, order)
{
    var prices = getPrices(tableData);
    var temp = trimPrices(prices);
    order = order.toLowerCase();
    switch(order)
    {
        case "descending":
        temp = sortParallelData(tableData, temp, order, {"data": tableData, "rows": rows}, orderTables);
        break;
        case "ascending":
        temp = sortParallelData(tableData, temp, order, {"data": tableData, "rows": rows}, orderTables);
        break;      
    }
}

function orderTables(tableData, tableCells)
{
   var rows = tableData['rows'];
   var data = tableData['data'];    
   for(var i=0;i<rows.length;i++)
   {
       var items = tableCells.slice(i * 4, (i * 4) + 4);
       var cells = data.slice(i * 4, (i * 4) + 4);
       for(var j=0;j<rows[i].childNodes.length;j++)
       {
           var node = rows[i].childNodes[j];
           rows[i].removeChild(node);   
       }
       for(var k=0;k<items.length;k++)
       {
           var item = items[k];
           var cell = cells[k];
           rows[i].appendChild(item);
       }
   }

}

function getPrices(tableData)
{
    var prices = [];
    for(var i=0;i<tableData.length;i++)
    {
        var data = tableData[i];
        var node = getElementNodes(data, "DIV", 1, {"class": "price-bold"})[0];
        var text;
        var whitespace;
        if(node.innerText)
        {
            text = node.innerText;
        }else if(node.textContent)
        {
            text = node.textContent;
        }
        whitespace = text.match(/\s+/);
        text = text.replace(whitespace, "");
        prices.push(text);
    }
    return prices;
}

function trimPrices(prices)
{
    var temp = [];
    for(var i=0;i<prices.length;i++)
    {
        var price = prices[i];
        temp.push(price.replace("$", "").replace(",", ""));
    }
    return temp;
}

function sortParallelData(first, second, order, data, callback)
{
    var matches = 0;
    var parallel = first;
    var cached = second;
    var left, right, temp;
    order = order.toLowerCase();   
    switch(order)
    {
        case "descending":
        for(var i=0;i<cached.length;i++)
        {
            left = parseInt(cached[i], 10);
            right = parseInt(cached[i+1], 10);
            temp = parallel[i+1];
            if(right > left)
            {
                cached[i+1] = left;
                parallel[i+1] = parallel[i];
                parallel[i] = temp;
                cached[i] = right;
                matches++;  
            }  
        }
        break;
        case "ascending":
        for(var i=0;i<cached.length;i++)
        {
            left = parseInt(cached[i], 10);
            right = parseInt(cached[i+1], 10);
            temp = parallel[i+1];
            if(left > right)
            {
                cached[i+1] = left;
                parallel[i+1] = parallel[i];
                parallel[i] = temp
                cached[i] = right;
                matches++;  
            }  
        }
        break;
    }
    if(matches > 0)
    {
        sortParallelData(first, second, order, data, callback);
    }else
    {
        callback(data, parallel);  
    }
}

http://jsfiddle.net/t6ysg/8/

Two assumptions were made, that being your table has a tbody tag containing your contents, and that you would always have 4 td elements per table row.

Tested as working in: Firefox 4, Chrome 4, Opera 11, Safari 4, IE 8 + Quirks, and IE 7 + Quirks.

Sign up to request clarification or add additional context in comments.

10 Comments

Matt... thanks for the hard work and going to the extra effort of creating a pure js solution. I've been working with the jsfiddle example and cannot seem to get it functioning. I've kept it to 4 TD elements within a TBODY like you suggested. Any chance I could get you to look at the jsfiddle example. I greatly appreciate your help.
Take a look at the markup in this example (note the location of the tbody): jsfiddle.net/t6ysg/9. So long as you keep the attributes the same, and 4 td elements per tr, it should work. In this next example, I've copy/pasted one tr element to illustrate that it still works: jsfiddle.net/t6ysg/10
@Matt... I followed your examples and notes. I've integrated the code you suggested into a more complex application. Following a little tweaking and minor adjustments the code is working beautifully. Thank you so much for your help and going to the extra effort of building a pure solution. Thanks again!
@Matt, +1 to see a pure javascript solution.
@Matt, The following line checks for the div class "price-bold". var node = getElementNodes(data, "DIV", 1, {"class": "price-bold"})[0]; Is there a way to check for two different class names i.e. "price" and/or "price-bold"? I've tried a number of if scenarios unsuccessfully. Thanks for your expertise.
|
1

You can simply call .sort() on the <td/> and in the sort find the price and do your comparison.

function SortItems(compare) {
    var elm = $("#contents-table td");
    elm.sort(function(a, b) {
        var priceAText = $(a).find(".price-bold").text().replace(/[^\d]/g, "");
        var priceA = parseFloat(priceAText);

        var priceBText = $(b).find(".price-bold").text().replace(/[^\d]/g, "");
        var priceB = parseFloat(priceBText);
        return compare(priceA, priceB);
    });
    //put them back in the table in the sorted order.
    $("#contents-table tr:first").append(elm.slice(0, 4));
    $("#contents-table tr:last").append(elm.slice(4, 8));
}

$("#high").toggle(function(){
    $(this).text("Sort Low");
    SortItems(function(a, b){ return a< b;});
}, function(){
    $(this).text("Sort High");
    SortItems(function(a, b){ return a> b;});
});

working jsfiddle example

fiddle with some simple fadeOut animation.

3 Comments

@Mark... thank you for the quick response and example. I appreciate your time. Cheers. ...Dan
@Mark... I have the code working. However, it does not support more than 8 objects. I believe due to the first and last statements. How would I express the statement with 20 rows per page and an undetermined number of pages? Thanks again for your help. ...Dan
@Dan, what you could do is slice up the elm into chunks and put them into the <tr/> in the sorted order. some pseduo code might be $("#contents-table tr").each(function(){//slice the elm})

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.