When I have a currently selected row in my jqgrid, and I have buttons that say "Next" and "Previous", how do I programmatically do that? Upon initial investigation, I'll need to get the ids of the rows but is there a way to do this by just using the index of the current selected row in the grid?
The ids in my rows are not sequential and are of random values.
Thanks
$('#btnNext').click(function () {
var grid = $("#grid").jqGrid({...});
var selectedRow = grid.getGridParam('selrow');
if (selectedRow == null) return;
var ids = grid.getDataIDs();
var index = grid.getInd(selectedRow);
if (ids.length < 2) return;
index++;
if (index > ids.length)
index = 1;
grid.setSelection(ids[index - 1], true);
});
According to http://www.trirand.com/jqgridwiki/doku.php?id=wiki:events, there's row index property but it doesn't get passed in to onSelectRow event. Perhaps you could get to the row object via its ID and check whether it has a row index, possibly called iRow. From there you'll just have to find the next row by row index iRow+1.
var rowId;
var previousRecord = false;
var array;
function initGrid() {
array = $(ProspectsGrid).jqGrid('getDataIDs');
var i = 0;
if (previousRecord == true)
i = array.length-1;
$(ProspectsGrid).setSelection(array[i]);
rowId = array[i];
}
function GetNextRecord() {
previousRecord = false;
if (rowId != array[array.length - 1]) {
var i = 0;
while (rowId != array[i]) {
i++;
}
i++;
$(ProspectsGrid).setSelection(array[i]);
rowId = array[i];
}
else {
var currentPage = ProspectsGrid.getGridParam("page");
if (currentPage < ProspectsGrid.getGridParam("lastpage")) {
ProspectsGrid.setGridParam({
page: currentPage + 1
});
ProspectsGrid.trigger("reloadGrid");
}
}
}
function GetPreviousRecord() {
previousRecord = true;
if (rowId != array[0]) {
var i = 0;
while (rowId != array[i]) {
i++;
}
i--;
$(ProspectsGrid).setSelection(array[i]);
rowId = array[i];
}
else {
var currentPage = ProspectsGrid.getGridParam("page");
if (currentPage > 1) {
ProspectsGrid.setGridParam({
page: currentPage - 1
});
ProspectsGrid.trigger("reloadGrid");
}
}
}
Related
I'm struggling in how to make this simple code work: i only want to check the values of every column and see if they are sequential (like 0 to 7 for example), and if so, highlight that column (class = "snaked" ).
So i marked every cell which belongs to the first row (class = "vstarter") and i tried out this :
function is_colsnake() {
ognicella.filter(".vstarter").each(
function() {
var cella = $(this);
var pos = cella.index();
var colonna = ognicella.filter(":nth-child(" + (pos + 1) + ")")
var col = [];
var issnake = false;
colonna.each(
function() {
col.push(parseInt($(this).text()));
});
col.each(
function() {
var start = parseInt($(this).text()) ;
var next = parseInt($(this).next().text()) ;
var prev = parseInt($(this).prev().text()) ;
var ix = $(this).index() ;
if (ix == 0) {
if (next == start + 1) {
issnake = true;
} else {
issnake = false;
}
} else if (start != prev + 1) {
issnake = false;
}
});
if (issnake) {
colonna.each(function() {
$(this).addClass("snaked");
})
} else {
colonna.each(function() {
$(this).removeClass("snaked");
})
}
})
};
However it isn't working. Would you please help?
I have a MultiSelectDropDown, that is, several RadComboBox controls are used in a combined way. For example, I can have a dropdown for regions, another for depots and another for user. The idea is to change the content of lower levels dynamically whenever items are selected or unselected on a higher level. The problem is that in the case when many items are selected, this becomes brutally slow due to some Telerik functions, but I do not understand why. This is a chunk from the client-side of the MultiSelectDropDown prototype:
changeLowerLevels: function (valueIndex, values, value) {
if (!this.canChange) return;
//Get selected values from combobox
var combo = $find(this.ddlIDs[valueIndex - 1]);
var cbItems = combo.get_checkedItems();
var selectedItems = [];
var change = null;
var counter = 0;
if (cbItems.length) this.filterString = "";
for (var i = 0; i < cbItems.length; i++) {
counter++;
if (this.filterString == "") this.filterString = cbItems[i].get_text();
selectedItems.push(cbItems[i].get_value());
}
if (counter > 1) this.filterString += " with " + (counter - 1) + " other" + ((counter > 2) ? "s" : "");
if (JSON.stringify(selectedItems) === JSON.stringify(this.selectedItems[valueIndex - 1]) || selectedItems == [])
return;
this.selectedItems[valueIndex - 1] = selectedItems;
var controlObject = this;
var combo = $find(this.ddlIDs[valueIndex]);
var comboItems = combo.get_items();
if(!this.disabled) combo.enable();
combo.clearItems();
if (valueIndex == 1) this.twoLevelCache = values;
var val = values;
//break if all items are found
var nrOfSelectedItems = this.selectedItems[valueIndex - 1].length;
var nrOfFoundItems = 0;
var index = 0;
var indexes = [];
var found = false;
while (nrOfFoundItems < nrOfSelectedItems && val[index] !== undefined) {
found = (this.selectedItems[valueIndex - 1].indexOf(val[index].Value) != -1);
if (!(found))
index++;
else {
indexes.push(index)
nrOfFoundItems++;
index++;
}
}
//separators from valuesIndex - 1 level
var controlObject = this;
for (var i = 0; i < indexes.length; i++) {
var separator = new Telerik.Web.UI.RadComboBoxItem();
separator.set_text("<span><a class=\"checkAll tt-multi-uncheck-icon\" index=\"" + index + "\">U</a>" + $find(this.ddlIDs[valueIndex - 1]).findItemByValue(val[indexes[i]].Value).get_text() + "</span>");
separator.set_value("");
separator.set_isSeparator(true);
comboItems.add(separator);
this.twoLevelCache.push(val[indexes[i]].Levels);
//valuesIndex level
var valuesArray = val;
var comboItem = new Telerik.Web.UI.RadComboBoxItem();
for (var depot in valuesArray[indexes[i]].Levels) {
comboItem = new Telerik.Web.UI.RadComboBoxItem();
comboItem.set_text(valuesArray[indexes[i]].Levels[depot].Name);
comboItem.set_value(valuesArray[indexes[i]].Levels[depot].Value);
comboItems.add(comboItem);
comboItem = null;
}
$('#' + this.ddlIDs[valueIndex] + '_DropDown a.checkAll').unbind().on("click", function () {
checkAllLowerItems(this, controlObject.ddlIDs[valueIndex]);
});
}
combo.set_emptyMessage(this.allText);
//$("#" + this.ddlIDs[valueIndex]).html(returnValue);
if (this.ddlIDs.length > valueIndex + 1) {
var paramToPass = (((val == undefined) || (val[index] === undefined)) ? ("") : (val[index]));
if (this.allText.length > 0)
this.changeLowerLevels(valueIndex + 1, paramToPass, "");
else {
if (paramToPass !== "")
paramToPass = paramToPass.Levels;
if ((val[index] == undefined) || (val[index].Levels[0] === undefined) || (val[index].Levels[0].Value === "")) {
this.changeLowerLevels(valueIndex + 1, paramToPass, "");
}
else {
this.changeLowerLevels(valueIndex + 1, paramToPass, val[index].Levels[0].Value);
}
}
}
else {
if (this.allText.length > 0)
this.selectedItems[valueIndex] = "";
else
if ((val[index] == undefined) || (val[index].Levels[0] === undefined) || (val[index].Levels[0].Value === "")) {
this.selectedItems[valueIndex] = "";
}
else {
this.selectedItems[valueIndex] = val[index].Levels[0].Value;
}
}
this.setText();
}
combo.clearItems() is extremeley slow. I have take a look on how it is implemented:
function (){var f=this._parent._getControl();?if(f._checkBoxes){f._checkedIndicesJson="[]";?f._checkedIndices=[];?var g=f.get_items();?for(var d=0,e=g.get_count();?d<e;?d++){var c=f.get_items().getItem(d);?c.set_checked(false);?}f.updateClientState();?}a.RadComboBoxItemCollection.callBaseMethod(this,"clear");?}
How can I make sure that this Javascript function speeds up?
I have finally solved the problem by rewriting Telerik client-side functionalities. It was a long and difficult debugging, but it yielded a large performance boost in the most difficult circumstances. From ~30 000 milliseconds, to ~300. Let's see the parts of the optimization:
The actual rewrite
/* Overriding Telerik functions Start */
var overridenTelerikControls = false;
function overrideTelerikFunctionalities() {
if (!overridenTelerikControls) {
overridenTelerikControls = true;
Telerik.Web.UI.RadComboBox.prototype.clearItems = function (isMultiSelectDropDown) {
this.get_items().clear(isMultiSelectDropDown);
this._itemData = null;
};
Telerik.Web.UI.RadComboBoxItemCollection.prototype.clear = function (isMultiSelectDropDown){
var f=this._parent._getControl();
if(f._checkBoxes){
f._checkedIndicesJson="[]";
f._checkedIndices=[];
var g = f.get_items();
for(var d=0,e=g.get_count();d<e;d++){
var c=f.get_items().getItem(d);
c.set_checked(false, isMultiSelectDropDown);
}
if (isMultiSelectDropDown) {
f._updateComboBoxText();
if (f._checkAllCheckBoxElement != null) {
f._updateCheckAllState();
}
}
f.updateClientState();
}
Telerik.Web.UI.RadComboBoxItemCollection.callBaseMethod(this, "clear");
};
Telerik.Web.UI.RadComboBoxItem.prototype.set_checked = function (d, isMultiSelectDropDown){
if(!this.get_enabled()){
return;
}
this._setChecked(d);
var c=this.get_comboBox();
if(c){
if(d){
c._registerCheckedIndex(this.get_index());
}else{
c._unregisterCheckedIndex(this.get_index());
}
if (!isMultiSelectDropDown) {
c._updateComboBoxText();
}
if((!isMultiSelectDropDown) && (c._checkAllCheckBoxElement!=null)){
c._updateCheckAllState();
}
}
};
}
}
/* Overriding Telerik functions End*/
My approach was to keep the old way of their working by default, but if an isMultiSelectDropDown parameter is passed, then work in the optimized manners. So we have a switch materialized as a parameter and we can turn it on/off. The main difference was that the old way was to change the label text showing the selected elements each time a checkbox is checked/unchecked. The main improvement was to do this change after all the checkboxes were checked/unchecked. This extremely simple idea was the driving force behind the boost of performance.
Actual usage
overrideTelerikFunctionalities();
combo.clearItems(true);
This was the functionalities were overriden if they were not already and the parameter was true, therefore the new approach was chosen.
Test, test, test
I have the following code:
function checkIfUnitCostItemsAreZero(finaliseIDList)
{
var selectedItems = finaliseIDList;
selectedItems = $.makeArray(selectedItems); //array is ["-2,-3"]
var getItem = $("#builderItemsList .listItem");
for (i = 0; i < getItem.length; i++)
{
var currentItem = ($(getItem[i]).attr("key"));
if (currentItem.indexOf(selectedItems) > -1)
{//currentItem = "-2" then "-3"
var unitCost = $(getItem[i]).attr("unitcost");
console.log(unitCost);
unitCost = parseFloat(unitCost);
if(unitCost==0.00)
{
return true;
break;
}
}
}
return false;
}
selected item currently equates to the following:
selectedItems = ["-2,-3"]
And further down, currentItem is evaluated at:
"-2", and the next loop "-3".
In both instances, neither go into the if statement. Any ideas why?
Courtesy of Hossein and Aer0, Fixed using the following:
String being passed in as a single value. Use split to seperate it for array.
Modify the if clause.
function checkIfUnitCostItemsAreZero(finaliseIDList)
{
var selectedItems = $.makeArray(finaliseIDList.split(','));
var getItem = $("#builderItemsList .listItem");
for (i = 0; i < getItem.length; i++) {
var currentItem = ($(getItem[i]).attr("key"));
if (selectedItems.indexOf(currentItem) > -1)
{
var unitCost = $(getItem[i]).attr("unitcost");
unitCost = parseFloat(unitCost);
if(unitCost==0.00)
{
return true;
break;
}
}
}
return false;
}
I can't force to select first row after applied filter. So when I'm loading my page to select first row I use:
gridApi.selection.selectRow($scope.gridOptions.data[0]);
this is from API documentation and it is clear.
Now, I'm trying to select first row after filter.
I have singleFilter function which comes from official documentation
$scope.singleFilter = function( renderableRows ){
var matcher = new RegExp($scope.filterValue);
renderableRows.forEach( function( row ) {
var match = false;
[
'name', 'company', 'email'
].forEach(function( field ){
if (field.indexOf('.') !== '-1' ) {
field = field.split('.');
}
if ( row.entity.hasOwnProperty(field) && row.entity[field].match(matcher) || field.length === 2 && row.entity[field[0]][field[1]].match(matcher)){
match = true;
}
});
if ( !match ){
row.visible = false;
}
});
var rows = $scope.gridApi.core.getVisibleRows();
var first = function(array, n) {
if (array == null){
return void 0;
}
if (n == null) {
return array[0];
}
if (n < 0) {
return [];
}
return array.slice(0, n);
};
console.log(first(rows))
$scope.gridApi.selection.selectRow(first(rows));
return renderableRows;
};
where I get the length of visible rows
var rows = $scope.gridApi.core.getVisibleRows();
thru simple script I get first row
var first = function(array, n) {
if (array == null){
return void 0;
}
if (n == null) {
return array[0];
}
if (n < 0) {
return [];
}
return array.slice(0, n);
};
console.log(first(rows))
then I'm trying to apply selection
$scope.gridApi.selection.selectRow(first(rows));
But unfortunately no success. Where is my mistake? I appreciate any help.
My plunker
I've created a working plunker below.
The reason this is not working is because the visible rows that you are getting is all of the rows, and not just the filtered rows. The reason that is all of the rows is because you are calling for them before returning the filter. I've created logic using what we are knowledgeable about at this point, which is what will be returned once the function completes.
http://plnkr.co/edit/LIcpOs7dXda5Qa6DTxFU
var filtered = [];
for (var i = 0; i < renderableRows.length; i++) {
if (renderableRows[i].visible) {
filtered.push(renderableRows[i].entity)
}
}
if (filtered.length) {
$scope.gridApi.selection.selectRow(filtered[0]);
}
I have to make some table-cells blink based on their values, and apparently IE8 is still a thing, so I'm working on the fix for that..
Here's my function for adding the blink-effect:
function blinkForIE(element) {
setInterval(function () {
if (element.hasClass('IEBlink')) {
element.removeClass('IEBlink');
}
else {
element.addClass('IEBlink');
}
}, 100);
}
the class:
.IEBlink
{
background-color:red;
}
This works for 4 of my 5 cells that should be blinking. I've debugged and checked taht the correct elements are getting passed to the blinkForIE-method and it adds the setInterval-thing for the first 4 elements but not the 5th..
Anyone knows why this might be happening? (I'm not sure what info might be needed, so if you need something else please comment and I'll add it when I can.)
EDIT: still not sure what you guys need to see, but here's all the jquery
var threshold = 100; //---THIS can be changed to what ever our threshold-difference should be.
$(document).ready(function () {
var itemsIndex;
var locationIndex;
var locations = [""];
$('#<%= gvKeying.ClientID %> tbody tr.GridHeader th').each(function () {
if ($(this).html() === 'Items') {
itemsIndex = $(this).index() + 1; //Find the column index of the Items column (+1 for nth-child usage)
}
else if ($(this).html() === 'KeyingLocation') {
locationIndex = $(this).index() + 1; //And the same for KeyingLocation-column.
}
});
$('#<%= gvKeying.ClientID %> tbody tr td:nth-child(' + locationIndex + ')').each(function () {
if ($(this).html() === ' ') {
//Do nothing.
}
else {
locations.push($(this).html()); //Add all locations to an array
}
});
locations = unique(locations); //Make them unique
locations.shift(); //This just removes the first empty element.
for (var i = 0; i < locations.length; i++) { //Loop through all locations
var values = [];
var valuesToBlink = [];
$('#<%= gvKeying.ClientID %> tbody tr').each(function () {
if ($(this).find('td:nth-child(' + locationIndex + ')').html() === locations[i]) {
values.push($(this).find('td:nth-child(' + itemsIndex + ')').html()); //Make an array with all the values.
}
});
values = getTop5(values); //We just want the top 5 highest values.
var firstBlinkVal = -1;
for (var j = 0; j < values.length - 1; j++) { //Loop through the values.
if (firstBlinkVal > -1 && compare(values[j], values[j + 1]) > -1) {
firstBlinkVal = Math.min(firstBlinkVal, compare(values[j], values[j + 1]));
}
else if(compare(values[j], values[j + 1]) > -1){
firstBlinkVal = compare(values[j], values[j + 1]);
}
}
if (firstBlinkVal > -1) {
for (var j = 0; j < values.length; j++) {
if (values[j] >= firstBlinkVal) {
valuesToBlink.push(values[j]);
}
}
}
$('#<%= gvKeying.ClientID %> tbody tr').each(function () { //Loop through all rows.
if ($(this).find('td:nth-child(' + locationIndex + ')').html() === locations[i]) { //If this row is the current location,
var temp = $(this).find('td:nth-child(' + itemsIndex + ')').html(); //get the value for this row.
if (jQuery.inArray(temp, valuesToBlink) > -1) { //if we want this to blink,
var ua = window.navigator.userAgent;
var msie = ua.indexOf("MSIE ");
if (msie > 0) {
blinkForIE($(this).find('td:nth-child(' + itemsIndex + ')')); //make it blink for IE
}
else {
$(this).find('td:nth-child(' + itemsIndex + ')').addClass('blink_me'); //make it blink for everything else.
}
}
}
});
}
});
function blinkForIE(element) {
var x = element.html();
console.log(x);
setInterval(function () {
if (element.hasClass('IEBlink')) {
element.removeClass('IEBlink');
}
else {
element.addClass('IEBlink');
}
}, 100);
}
//This just compares two values and returns true if the diff is over our threshold.
function compare(val1, val2) {
if (Math.abs(val1 - val2) > threshold) {
return Math.max(val1, val2);
}
return -1;
}
//Returns a sorted array of the top5 highest values in the input-array.
function getTop5(values) {
values.sort(function (a, b) { return b - a });
while (values.length > 5) {
values.pop();
}
values.sort(function (a, b) { return a - b });
return values;
}
//Makes the values of the input unique.
function unique(list) {
var result = [];
$.each(list, function (i, e) {
if ($.inArray(e, result) == -1) result.push(e);
});
return result;
}
You should call only 1 setInterval function, passing all cells to be animated.
function blinkForIE(elements) {
setInterval(function(){
elements.forEach(function(e){$(e).toggleClass('IEBlink')})
}, 100);
}
resp.
function blinkForIE($elements) {
setInterval(function(){
$elements.toggleClass('IEBlink')
}, 100);
}
(elements is Array, $elements is jQuery object)
The problem is, that setInterval must not execute the callback function, if there is no idle time slot at the execution time. It happens, when there are many executions within a small time interval.
You can troubleshoot this also using different offsets:
setTimeout(function(){setInterval(callback, 100)}, i*15)