Blindsyde Blindsyde - 1 month ago 16
jQuery Question

Use jqgrid to filter in the same way searching is done

Let me see if I can explain this...

I have a product grid, searching works fine, I have set up a custom button to filter on specific items in the json that are not in the grid, right now I am making an ajax call (using VisualForce) to get the json then I'm storing it in a global variable before using the json to load the grid, I then load the grid. When a filter is chosen I build a temp array of the json that contains the filter and then set the product grid to the new array. I then have a reset so if the filter is changed or removed it will first get the global that I set earlier and the re-apply a new filter, however when I

clearGridData
it empties my global variable as well so when I click reset it just reloads the grid with zero rows.

I am guessing what I am doing is the wrong way to do it so I am wondering how does the search work, you search for an item it shows only the matches in the grid and then simply pressing reload it reloads all records back into grid. I need my filter to work somewhat the same.

var cart = [];
var cartMade = false;
var cartSubmitted = false;
var sfOpportunityId;
var filteredProducts = [];
var fullProductList = [];

function GetFilteredProducts(){
//reload products with filtered array
var products = $("#productsTable").jqGrid('getGridParam','data');
var selected = $("#filterByFieldDropDown option:selected").val();
switch(selected){
case "common" :
filteredProducts = $.grep(products, function(value) {
return value.IsCommonItem == true;
});
break;
case "sos-common" :
filteredProducts = $.grep(products, function(value) {
return value.IsCommonSosItem == true;
});
break;
case "uncommon" :
filteredProducts = $.grep(products, function(value) {
return value.IsCommonItem == false;
});
break;
}
RemoveProductFilter();
$("#productsTable").jqGrid('clearGridData')
.jqGrid('setGridParam', { data: filteredProducts})
.trigger("reloadGrid");
}

function RemoveProductFilter() {
$("#productsTable").jqGrid('clearGridData')
.jqGrid('setGridParam', { data: fullProductList})
.trigger("reloadGrid");

$("#filter-dialog-form").dialog("close");
}

function QueryServerForProducts() {
$(".spinner").show();
var ajaxCall = '{!$RemoteAction.AddProductsCustom.GetProducts}';
sfOpportunityId = requestQueryString("id")
GetCart();
// Get Products and put them into product grid
Visualforce.remoting.Manager.invokeAction(
ajaxCall,
sfOpportunityId,
function(result, event){
if (event.status) {
$(".spinner").hide();
var parsedResult = JSON.parse(DecodeAscii(result));
fullProductList = parsedResult;
CreateProductGrid(parsedResult);
} else if (event.type === 'exception') {
ShowErrorLabel("ERROR in ajax call(" + ajaxCall + "): \n" + event.message);
} else {
ShowWarningLabel("Problem w/ ajax call(" + ajaxCall + "): \n" + event.message);
}
},
{escape: true}
);
}

function CreateProductGrid(result){
var previouslySelectedRow = null;
var rowIsSelected = null;
var previousRowIsSelected = null;
var currentRowId;
var currentCount;
var cancelEditing = function(theGrid) {
var lrid;
if (typeof previouslySelectedRow !== "undefined") {
// cancel editing of the previous selected row if it was in editing state.
// jqGrid hold intern savedRow array inside of jqGrid object,
// so it is safe to call restoreRow method with any id parameter
// if jqGrid not in editing state
theGrid.jqGrid('restoreRow', previouslySelectedRow);

// now we need to restore the icons in the formatter:"actions"
lrid = $.jgrid.jqID(previouslySelectedRow);
$("tr#" + lrid + " div.ui-inline-edit").show();
$("tr#" + lrid + " div.ui-inline-save, " + "tr#" + lrid + " div.ui-inline-cancel").hide();
}
};

$("#productsTable").jqGrid({
data: result,
datatype: "local",
colNames: [
'Add', 'Product Name', 'Product Code', 'Customer Price'
],
colModel: [
{ name: "actions", template: "actions", width: 50, formatoptions:{
delbutton: false,
editbutton: false
}},
{ name: 'ProductName', index: 'ProductName', width: 650, search: true, searchoptions:{sopt:['eq','bw','bn','cn','nc','ew','en']} },
{ name: 'ProductCode', index: 'ProductCode', width: 150, search: true, searchoptions:{sopt:['eq','bw','bn','cn','nc','ew','en']} },
{ name: 'UnitPrice', index: 'UnitPrice', width: 100, search: false, formatter: 'currency', formatoptions:{decimalSeparator:".", thousandsSeparator: ",", decimalPlaces: 2, prefix: "$"}}
],
rowNum: 25,
rowList: [15, 25, 50, 100],
pager: true,
viewrecords: true,
sortname: 'ProductName',
iconSet: "fontAwesome",
sortorder: 'asc',
localReader: {id: "ProductId" },
caption: "Products",
navOptions: {
edit: false,
add: false,
del: false,
searchtext: "<span class='ui-pg-button-text'>Search</span>",
refreshtext: "<span class='ui-pg-button-text'>Reload</span>",
iconsOverText: true
},
inlineNavOptions: {
edit: false,
add: false,
del: false
},
searching: {
overlay: false,
multipleSearch: true,
closeAfterSearch: true,
closeOnEscape: true,
showQuery: true
},
actionsNavOptions: {
addToCarticon: "fa-shopping-cart",
addToCarttitle: "Add product to the cart",
custom: [
{ action: "addToCart", position: "first", onClick: function (options) {
var rowData = $('#productsTable').getLocalRow(options.rowid);
var cartButton = $("#jAddToCartButton_"+options.rowid).find("span");
if(cartButton.hasClass("fa-ban")){
DeleteProductFromOpportunity(JSON.stringify(rowData));
cart = $.grep(cart, function(value) {
return value.ProductId !== rowData.ProductId;
});
//reload cart with new array
reloadCart();
cartButton.removeClass("fa-ban");
cartButton.addClass("fa-shopping-cart");
}
else if(cartButton.hasClass("fa-shopping-cart")){
cart.push(rowData);
//reload cart with new array
reloadCart();
cartButton.removeClass("fa-shopping-cart");
cartButton.addClass("fa-ban");
}
}
}]
},
loadComplete: function() {
//for each object in cart
//if product ID matches product Id in product
//grid then set button to a cancel icon
if(cart.length !== 0){
var cartIds = [];
var jsonCart = JSON.stringify(cart);
var parsedJsonCart = JSON.parse(jsonCart);
var productsInCart = $.grep(parsedJsonCart, function(el, i){
cartIds.push(el.ProductId);
});

var currentRows = $('#productsTable').jqGrid('getGridParam', 'data')
var shownProductsThatAreInCart = $.grep(currentRows, function (el, i) {
return $.inArray(el.ProductId, cartIds) !== -1;
});

if(shownProductsThatAreInCart.length > 0){
var rowIds = $(this).jqGrid('getDataIDs');
$.each(rowIds, function(k, v) {
rowData = $('#productsTable').getLocalRow(v);

if($.inArray(rowData['ProductId'], cartIds) !== -1){
//alert("Matched Product:\nRowData['ProductId'] = " + rowData['ProductId'] + "\nto\nProduct in cart: " + cartIds.Id);
var cartButton = $("#jAddToCartButton_"+v).find("span");
cartButton.removeClass("fa-shopping-cart");
cartButton.addClass("fa-ban");
}
});
}
}
}
})
.jqGrid('navGrid')
.jqGrid("navButtonAdd", {
iconsOverText: true,
caption:"<span class='ui-pg-button-text'>Filter</span>",
buttonicon: "fa-filter",
onClickButton: function() {
InitializeFilterDialog();
$("#filter-dialog-form").dialog("open");
},
title:"Filter",
position: "first"
})
.jqGrid("navButtonAdd", {
iconsOverText: true,
caption:"<span class='ui-pg-button-text'>View Cart</span>",
buttonicon: "fa-shopping-cart",
onClickButton: function() {
InitializeProductCartDialog();
ShowCart();
},
title:"View Cart"
});
}

Answer

I'd recommend you to load all the data and just apply the filter on the grid. The fixed code could be the following:

var mydata = [
        {"id":"1","invdate":"2010-05-24","name":"test","note":"note","tax":"10.00","total":"2111.00","isCommon":"true","isCommonSos":"true"},
        ...
        {"id":"29","invdate":"2007-09-01","name":"test3","note":"note3","amount":"400.00","tax":"30.00","total":"430.00","isCommon":"true","isCommonSos":"false"}
    ],
    $grid = $("#productsTable");

$grid.jqGrid({
    data: mydata,
    rowNum: 10,
    rowList: [10,20,30],
       colNames:['Inv No','Date', 'Client', 'Amount','Tax','Total','Notes'],
       colModel:[
           {name:'id', width:60, sorttype:"int"},
           {name:'invdate', width:90, sorttype:"date", formatter:"date"},
           {name:'name', width:100},
           {name:'amount', width:80, align:"right",sorttype:"float", formatter:"number"},
           {name:'tax', width:80, align:"right",sorttype:"float"},        
           {name:'total', width:80,align:"right",sorttype:"float"},        
           {name:'note', width:100, sortable:false}        
       ],
       pager: true,
       viewrecords: true,
       caption: "Filtering Array Data",
       additionalProperties: ["isCommon", "isCommonSos"],
       iconSet: "fontAwesome"
});

$("#applyFilter").on("click", function() {
    GetFilteredProducts();
});

$("#clearFilter").on("click", function() {
    var p = $grid.jqGrid("getGridParam");
    delete p.postData.filters;
    p.search = false;
    $grid.trigger("reloadGrid");
});

function GetFilteredProducts(){
  //reload products with filtered array
  var selected = $("#filterByFieldDropDown").val(),
      p = $grid.jqGrid("getGridParam");

  switch(selected){
    case "common" :
      p.postData.filters = JSON.stringify({
          groupOp: "AND",
          groups: [],
          rules: [{field: "isCommon", op: "eq", data: "true"}]
      });
      break;
    case "sos-common" :
      p.postData.filters = JSON.stringify({
          groupOp: "AND",
          groups: [],
          rules: [{field: "isCommonSos", op: "eq", data: "true"}]
      });
      break;
    case "uncommon" :
      p.postData.filters = JSON.stringify({
          groupOp: "AND",
          groups: [],
          rules: [{field: "isCommon", op: "eq", data: "false"}]
      });
      break;
  }
  p.search = true;
  $grid.trigger("reloadGrid");
}

See the fixed demo https://jsfiddle.net/OlegKi/36wkfzs4/2/.

Free jqGrid support filtering and sorting by any additional properties of input data in the same way like by columns. If you need to filter/sort by string properties you can just add the list of properties in additionalProperties, like I used additionalProperties: ["isCommon", "isCommonSos"] in the above demo. You can use the properties as the value of sortname too, to force sorting by the property.

If you would like to interpret the content of the property as number or integer then you can use another form of additionalProperties: and object with two properties name and sorttype. For example you can remove the column id and to use additionalProperties: ["isCommon", {name: "id", sorttype: "integer"}, "isCommonSos"]. To interpret the data as date you should add formatter: "date". You can specify formatoptions with srcformat and newformat additionally. In general the format of additionalProperties for numbers and date could be subset of settings used in colModel. You can just move some columns, which you want hold always hidden to additionalProperties and all will work in the same way like with hidden columns, but the DOM of the grid will be smaller.

Comments