JQGrid - copying selected rows between grids - javascript

I have two grids that I allow the user to copy rows between. For small sets, no problem, but for large datasets (5-10 thousand) I notice JQGrid is very slow. This is what I have now:
$('#imgRightArrow').click(function ()
{
var fromGrid = $('#fromGrid');
var toGrid = $('#toGrid');
var rowKeys = fromGrid.getGridParam('selarrrow');
var j = rowKeys.length - 1;
if (j >= 0) $('body').addClass('loading');
(function ()
{
for (; j >= 0; j--) // - high to low to avoid id reordering
{
var row = fromGrid.jqGrid('getRowData', rowKeys[j]);
toGrid.addRowData('gtp_' + rowKeys[j], row); // - add prefix to keep rowid's unique between grids
fromGrid.delRowData(rowKeys[j]);
if (j % 100 === 0)
{
$('#fromGridHeader').text(fromGrid.jqGrid('getGridParam', 'records') + ' Cards on this Order');
$('#toGridHeader').text(toGrid.jqGrid('getGridParam', 'records') + ' Cards to be Dispatched');
if (j === 0) // - done
$('body').removeClass('loading');
else
{
j--;
window.setTimeout(arguments.callee); // - set a timer for the next iteration
break;
}
}
}
})();
});
It's so slow that I have to use a kludge to prevent the browser from timing out.
I've tried something like this:
$('#imgRightArrow').click(function ()
{
var fromGrid = $('#fromGrid');
var toGrid = $('#toGrid');
var copyData = toGrid.jqGrid('getRowData'); // - existing data
var rowKeys = fromGrid.getGridParam('selarrrow');
var j = rowKeys.length - 1;
if (j >= 0) $('body').addClass('loading');
(function ()
{
for (; j >= 0; j--)
{
copyData.push(fromGrid.jqGrid('getRowData', rowKeys[j]));
fromGrid.jqGrid('delRowData', rowKeys[j]);
if (j % 100 === 0)
{
if (j === 0)
{
fromGrid[0].refreshIndex();
toGrid.jqGrid('clearGridData', true);
toGrid.setGridParam({ data: copyData });
toGrid[0].refreshIndex();
toGrid.trigger('reloadGrid');
$('#fromGridHeader').text(fromGrid.jqGrid('getGridParam', 'records') + ' Cards on this Order');
$('#toGridHeader').text(toGrid.jqGrid('getGridParam', 'records') + ' Cards to be Dispatched');
$('body').removeClass('loading');
}
else
{
j--; // - manually decrement since we break
window.setTimeout(arguments.callee); // - set a timer for the next iteration
break;
}
}
}
})();
});
...it seems faster, but deleting the rows from the fromGrid still uses delRowData, which is very slow.
Any ideas on how to accomplish this efficiently for large sets of data?

Any client-side operation is going to be very slow when you have thousands of rows involved. The best way to speed it up would be to do the operations server-side. For example, you could pass the ID's to the server as part of an AJAX request and then refresh the grids when the server response is received.
Alternatively, is the user really selecting five thousand rows to copy, or are they just trying to do a bulk operation such as "copy all"? Maybe you can implement such a feature to improve the overall experience, and eliminate the need to pass any ID's to the AJAX request.
Does that help?

By pressing ctrl+c we can copy and paste the selected row using the following methods,
$(document).ready(function () {
$('#gvMygrid').keyup(function (e) {
var crtlpressed = false;
var celValue = "";
var celValue1 = "";
var celValue2 = "";
if (e.keyCode == 17) {
crtlpressed = true;
}
if (e.keyCode == 67 && e.ctrlKey == true) {
var myGrid = $('#gvMygrid');
var my_array = new Array;
my_array = $("#gvMygrid").getGridParam('selarrrow');
for (var i = 0; i < my_array.length; i++) {
var rowInfo = $("#gvMygrid").getRowData(my_array[i]);
if (rowInfo != null)
var data = JSON.stringify(rowInfo);
var splitData = data.split('","');
for (var j = 1; j < splitData.length; j++) {
celValue1 = celValue1 + splitData[j].split(":")[1] + " ";
}
celValue1 = celValue1 + '\r\n';
}
celValue2 = celValue1.replace(/"/g, '');
celValue = celValue2.replace(/}/g, '');
crtlpressed = false;
copyToClipboard(celValue);
}
function copyToClipboard(s) {
if (window.clipboardData && clipboardData.setData) {
window.clipboardData.clearData("Text");
clipboardData.setData("Text", s);
}
}
}); });
We are splitting the data with a four spaces in the for loop so that we can get each cells data with four spaces.

Related

JavaScript infinity loop in calculator

I'm developing a small calculator that allows you to input a string. So it has to recognize which sign has to be executed in first place.
My problem is that somewhere and by some reason it creates a stackoverflow. I was expecting if you could help me to find out.
The first for is to give each operator a precedence, so * is more important than +. Second loop is destinated to find the sign into the string, so if input.indexOf(signos[i]) is lower or than 0 it jumps off the operator. if its dalse it goes in and put the number in left side and right side into two aux values and in the end it solves the sign and replace it into the string so at the end it shows you the result.
Thanks.
var input;
var signos = ['*', '/', '+', '-'];
var cursor = 0;
var aux1 = "";
var aux2 = "";
var auxSigno = "";
var resuelto = 0;
var encontrado = false;
function lectura(){
input = document.getElementById("ans").value;
console.log(input);
for(i = 0; i < signos.length; i++){
cursor = input.indexOf(signos[i]);
//console.log(cursor);
if (cursor > -1){
auxSigno = input.charAt(cursor);
//console.log(auxSigno);
for(j = 0; j < input.length; i++){
for(k = cursor-1; comparar(k); k--){
aux1+=input[k];
}
for(l = cursor+1; comparar(l); l++){
aux2+=input[l];
}
operar();
var cadena = aux1+auxSigno+aux2;
var auxCadena = input.replace(cadena, resuelto);
input = auxCadena;
}
}
}
console.log(input);
}
function comparar(caracter){
for(m = 0; m < signos.length; m++){
if (caracter === signos[m]){
return true;
}
}
return false;
}
function operar(){
console.log(auxSigno);
console.log(aux1);
console.log(aux2);
if (signos.indexOf(auxSigno) == 0){
resuelto = parseFloat(aux1) * parseFloat(aux2);
console.log(resuelto + " opc1");
} else if (signos.indexOf(auxSigno) == 1) {
resuelto = parseFloat(aux1) / parseFloat(aux2);
console.log(resuelto + " opc2");
} else if (signos.indexOf(auxSigno) == 2) {
resuelto = parseFloat(aux1) + parseFloat(aux2);
console.log(resuelto + " opc3")
} else if (signos.indexOf(auxSigno) == 3){
resuelto = parseFloat(aux1) - parseFloat(aux2);
console.log(resuelto + " opc4")
} else {
console.log("opc no implementada");
}
}
if the input is "6+6*8", the result should be "54", but it doesn't show anything, just keep doing the for.

How to optimise RadComboBox clearItems function

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

setInterval only running on 4 of my 5 elements

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)

Javascript For Loop interrupted by function call?

I have a for-loop that is terminating without finishing the loop. It seems to be related to whether or not a call to another function is made within the loop.
this.cycle = function() {
var list = this.getBreaches("Uncontained");
if (list.length > 0) {
for (i=0; i < list.length; i++) {
this.saveVsRupture(DC=11, i); //calls this.rupture() if save failed
}}
return 1;
};
this.saveVsRupture() calls a function that rolls a d20 and checks the result. If the save fails, it calls a method called this.rupture() that does some adjusting to this.
Problem
If the saving throw is successful, the loop continues, but if the saving throw fails, it runs the this.rupture() function and then breaks the for-loop. It should keep running the for-loop.
Why is this happening?
Additional Details
Here are the other functions...
savingThrow = function(DC=11) {
// DC = Difficulty Check on a d20
try {
if (0 <= DC) {
var roll = Math.floor((Math.random() * 20))+1; //roll d20
var msg = "(Rolled "+roll+" vs DC "+DC+")";
console.log(msg);
if (roll >= DC) { //Saved
return true;
}
else { //Failed save
return false;
}
}
}
catch(e) {
console.log("Exception in savingThrow: "+e);
};
};
this.saveVsRupture = function(DC=1, i=null) {
try {
if (!savingThrow(DC)) {
this.rupture(i);
return false;
}
return true;
}
catch(e) {
console.log(e);
}
};
this.rupture = function(i=null) {
if (i == null) {
i = range(1,this.damageList.length).sample();
}
var hole = this.damageList[i];
var dmg = range(1,this.harmonics()).sample();
hole.rupture(dmg);
msg = "*ALERT* " + hole + " expanded by " + dmg + "% Hull Integrity #"+this.hullIntegrity();
this.log(msg);
if (hole.size % 10 == 0) {
this.health -= 25;
msg = "The ship creaks ominously.";
this.log(msg);
}
return 1;
};
The correct syntax for the for-loop declares the counter variable.
for (var i=0; i < list.length; i++) {etc..
/// Causes the For-Loop to exit prematurely...
for (i=0; i < list.length; i++) {etc..
Once the "var i=0" is used, the for-loop operates as expected.
consider implementing a try-catch in your for loop, with your saveVsRupture function within the try. This implementation will catch errors in your function but allow the program to keep running.
Change the saveVsRupture function like this:
function saveVsRupture(a,b) {
try{
//your saveVsRupture code here...
}
catch(e){}
}
Your should catch problems that occurred in your code with try,catch block to prevent throw them to top level of your code (the browser in this example) .
Don't use return in for loop!
Change your code as following:
this.cycle = function() {
var list = this.getBreaches("Uncontained");
if (list.length > 0) {
for (i=0; i < list.length; i++) {
var temp = this.saveVsRupture(DC=11, i); //calls this.rupture() if save failed
console.log(temp);
}}
return 1;
};

My javascript crashes the server

Now before everyone is helpful (seriously, you guys are awesome) I am doing a coding challenge that means I can't get code from other users/people. This does not, however, extend to advice so I wanted to know why my code crashes google chrome. I don't want am not allowed any code so please just point me in the right direction. I am sorry for such an odd request but I am at my wit's end.
http://jsfiddle.net/clarinetking/c49mutqw/9/
var chars;
var keyword = [];
var cipher;
var done = false;
var list1 = [];
var list2 = [];
var list3 = [];
var list4 = [];
var list5 = [];
var keylngth = 0;
$('#apnd').click(function () {
cipher = $('#Input').val();
chars = cipher.split('');
$('#Output').append(chars);
});
$('#key').click(function () {
while (done === false) {
var letter = prompt('insert letter, xyz to close');
keylngth++;
if (letter == 'xyz') {
done = true;
} else {
//Push letter to keyword array
keyword.push(letter);
}
}
});
$('#list').click(function () {
for (i = 0; i < chars.length; i++) {
var x = 1;
for (i = 1; i < keylngth+1; i++) {
if (i/x === 1) {
list1.push(chars[x]);
}
if (i/x === 2) {
list1.push(chars[x]);
}
if (i/x === 3) {
list1.push(chars[x]);
}
if (i/x === 4) {
list1.push(chars[x]);
}
if (i/x === 5) {
list1.push(chars[x]);
}
if (i/x === 6) {
list1.push(chars[x]);
}
if (i/x === 7) {
list1.push(chars[x]);
}
if (i/x === 8) {
list1.push(chars[x]);
}
}
x++;
}
alert(list1);
alert(list2);
});
I apologize to all you coders out there that are probably screaming at me USE A REPEAT LOOP! but for the list function I see no way to. As previously mentioned, no code please unless it's pseudo code :)
In your $('#list').click(function ()) function you are running an infinite for bucle, it's because you use the same i counter for the two for bucles so you javascript will run forerver and crash the browser

Categories

Resources