How do I compress this duplicate code and make it dynamic?

77 views Asked by At

I have some duplicate code to add dropdown filters to my DataTable (using jQuery DataTables plugin) that looks something like this:

// filter based on company type
$.fn.dataTable.ext.search.push(
    function( settings, data, dataIndex ) {
        selectedType = $('#companyType').val();
        if(selectedType.toLowerCase() === "all"){
            return true;    
        }
        if(selectedType.toLowerCase() === data[2].toLowerCase()){
            return true;                    
        }
        return false;
    }
);

// filter based on status type
$.fn.dataTable.ext.search.push(
    function( settings, data, dataIndex ) {
        selectedType = $('#status').val();
        if(selectedType.toLowerCase() === "all"){
            return true;    
        }
        if(selectedType.toLowerCase() === data[3].toLowerCase()){
            return true;                    
        }
        return false;
    }
);

// filter based on account type
$.fn.dataTable.ext.search.push(
    function( settings, data, dataIndex ) {
        selectedType = $('#accountType').val();
        if(selectedType.toLowerCase() === "all"){
            return true;    
        }
        if(selectedType.toLowerCase() === data[9].toLowerCase()){
            return true;                    
        }
        return false;
    }
);

As you can see, the only differences between these functions is the elementID (of the filter dropdown) and the column index. I'd like to factor out the duplicate code and make it reusable, using a loop or a function.

I tried using a key-value object in javascript and then looping through to add a filter for each:

<!--- Create object that stores key-value pairs for all dropdown filters; key is column index, value is filter element ID --->
var dropDownFilters = { 2: "companyType", 3: "status", 9: "accountType" }
<!--- Loop through dropdown filters and set filter for each --->
for(var key in dropDownFilters){
    $.fn.dataTable.ext.search.push(
        function( settings, data, dataIndex ) {
            selectedType = $('#' + dropDownFilters[key]).val();
            if(selectedType.toLowerCase() === "all"){
                return true;    
            }
            if(selectedType.toLowerCase() === data[key].toLowerCase()){
                return true;                    
            }
            return false;
        }   
    );      
}

This doesn't work properly as it only creates the filter function with the last values (9 and accounttype), so the third filter works but the others don't.

I can accomplish what I'm looking to accomplish through server-side coldfusion code on load:

<cfset dropDownFilters = [  { colIndex=2, elementID = "companyType" }, 
                            { colIndex=3, elementID = "status"},
                            { colIndex=9, elementID = "accountType"} ] />
<cfloop from="1" to="#ArrayLen(dropDownFilters)#" index="i">
    $.fn.dataTable.ext.search.push(
        function( settings, data, dataIndex ) {
            selectedType = $('#<cfoutput>#dropDownFilters[i].elementID#</cfoutput>').val();
            if(selectedType.toLowerCase() === "all"){
                return true;    
            }
            if(selectedType.toLowerCase() === data[<cfoutput>#dropDownFilters[i].colIndex#</cfoutput>].toLowerCase()){
                return true;                    
            }
            return false;
        }   
    );
</cfloop>

However, this feels clunky. I'd prefer to accomplish this through pure javascript, there's no reason to involve ColdFusion.

How can I refactor this duplicate code using a loop or a function (and which is preferable)?

1

There are 1 answers

2
suvroc On

You can create function to reuse some code. Code duplication is one of antipattern in programming.

function prepare(selector, index)
{
    $.fn.dataTable.ext.search.push(
        function( settings, data, dataIndex ) {
            selectedType = $(selector).val();
            if(selectedType.toLowerCase() === "all"){
                return true;    
            }
            if(selectedType.toLowerCase() === data[index].toLowerCase()){
                return true;                    
            }
            return false;
        }
    );
}

and then your code would look like:

prepare('#companyType', 2);
prepare('#status', 3);
prepare('#accountType', 9);