Redefine click selector jQuery - javascript

I am trying to make jQuery update the values in the selector after they are passed. What I mean is this.
I am passing the selector like this.
var items = ['.item-1','.item-2'...];
$(items[1]).click(function(){....});
And then in the end of the function I change the order of the items array.
var items = ['.item-1','.item-2'...];
$(items[1]).click(function(){
// ... function
items = ['.item-3', '.item-1' ...];
});
Now the problem is that the function is binded to the inital items[1], so my changing of the array does not really matter. I am pretty sure there should be a not too complicated solution, so can you please point me in the right direction ?

You could one method in combination with a recursion schema
var items = ['.item-1','.item-2','.item-3'];
$(items[1]).one('click', clickHandler);
function clickHandler() {
items = //re-sort items;
$(items[1]).one('click', clickHandler);
}
Take into account that arrays index is zero based so you're using the second item and not the first when doing items[1].

I think you have to use a recursive method.
It could be:
var items = ['.item-1','.item-2'];
function redefine(){
$(items[1]).click(function(){
items = ['.item-3', '.item-1'];
$(this).unbind("click");
redefine();
});
}
redefine()

Related

Iterating over rows of table

I'm am iterating over dynamically generated div which contains a table. While I'm iterating over rows, Suppose I'm having two rows, I'm getting two results. But the problem is that both the results contain values of last row of table. Here is my code:
$(this)
.children('.js-charge-data')
.children('.js-charging-line-wrapper')
.find('.js-chargeline-tbody')
.children('tr')
.each(function() {
chargingLineJSON['chargingType'] = 'IoT';
chargingLineJSON['chargeCategoryName'] = $(this).find('.js-charging-category').val().trim();
chargingLineJSON['subCategoryName'] = $(this).find('.js-charging-sub-category').val().trim();
chargingLineJSON['backEndProductName'] = $(this).find('.js-charging-sub-category').children(':selected').data('backend_product_name');
chargingLineJSON['shipToAddressId'] = '123';
chargingLineJSON['chargePerUnit'] = $(this).find('.js-unit-charge').val().trim();
chargeLineListJSON['chargingLine'] = chargingLineJSON;
chargingLineJSONArray.push(chargeLineListJSON);
});
Please let me know what mistake am I doing?
You are pushing same object chargingLineJSON to the array, Create a new object in the .each() block
.each(function () {
//Create a new object
var chargingLineJSON = {};
//Your code
chargingLineJSONArray.push(chargeLineListJSON);
});
As per #Rajesh comment
Objects are copied using reference. So in second iteration, when you set value to object's property, you are overriding value at a memory location and not in a locat variable. Hence, same values
As commented and credited in #Satpal's answer, issue is due to object copied as a reference.
Not repeating the comment in my answer though to reduce duplication of data.
You can use something like this.
$(this)
.find('.js-charge-data .js-charging-line-wrapper .js-chargeline-tbody tr')
.each(function() {
let category = $(this).find('.js-charging-category');
let subCategory = $(this).find('.js-charging-sub-category');
let selectedSubCategory = $(this).find('.js-charging-sub-category :selected');
let unitCharge = $(this).find('.js-unit-charge');
chargingLineJSONArray.push({
chargingType: 'IoT',
shipToAddressId: '123'
chargeCategoryName: category.val().trim(),
subCategoryName: subCategory.val().trim(),
backEndProductName: selectedSubCategory.data('backend_product_name'),
chargePerUnit: unitCharge.val().trim()
});
// Not sure what this line is about?
// You are saving reference to self in a property.
// chargeLineListJSON['chargingLine'] = chargingLineJSON;
});
Note: I have not tested code as mark is missing.

What is a faster way to write this function to delete rows/objects in a table?

So, I have this function that, after an update, deletes elements from a table. The function, lets call it foo(), takes in one parameter.
foo(obj);
This object obj, has a subfield within called messages of type Array. So, it would appear something like this:
obj.messages = [...];
Additionally, inside of obj.messages, each element contains an object that has another subfield called id. So, this looks something like:
obj.messages = [{to:"You",from:"Me",id:"QWERTY12345.v1"}, ...];
Now, in addition to the parameter, I have a live table that is also being referenced by the function foo. It uses a dataTable element that I called oTable. I then grab the rows of oTable and copy them into an Array called theCurrentTable.
var theCurrentTable = oTable.$('tr').slice(0);
Now, where it gets tricky, is when I look into the Array theCurrentTable, I returned values appear like this.
theCurrentTable = ["tr#messagesTable-item-QWERTY12345_v1", ...];
The loop below shows how I tried to show the problem. While it works (seemingly), the function itself can have over 1000 messages, and this is an extremely costly function. All it is doing is checking to see if the current displayed table has the elements given in the parameter, and if not a particular element, delete it. How can I better write this function?
var theCurrentTable = oTable.$('tr').slice(0);
var theReceivedMessages = obj.messages.slice(0);
for(var idx = 0; idx < theCurrentTable.length; idx++){ // through display
var displayID = theCurrentTable[idx].id.replace('messagesTable-item-','').replace('_','.');
var deletionPending = true;
for(var x = 0; x < theReceivedMessages.length; x++){
var messageID = theReceivedMessages[x].id;
if(diplayID == messageID){
console.log(displayID+' is safe...');
deletionPending = false;
}
}
if(deletionPending){
oTable.fnDeleteRow(idx);
}
}
I think I understand your problem. Your <tr> elements have an id that should match an item id within your messages.
First you should extract the message id values you need from the obj parameter
var ids = obj.messages.map(function (m) { return '#messagesTable-item-' + m.id; });
This will give you all the rows ids you need to keep and then join the array together to use jQuery to select the rows you don't want and remove them.
$('tr').not(ids.join(',')).remove();
Note: The Array.prototype.map() function is only supported from IE9 so you may need to use jQuery.map().
You could create a Set of the message ID values you have, so you can later detect if a given ID is in this Set in constant time.
Here is how that would look:
var theCurrentTable = oTable.$('tr').slice(0);
var theReceivedMessages = obj.messages.slice(0);
// Pre-processing: create a set of message id values:
var ids = new Set(theReceivedMessages.map( msg => msg.id ));
theCurrentTable.forEach(function (row, idx) { // through display
var displayID = row.id.replace('messagesTable-item-','').replace('_','.');
// Now you can skip the inner loop and just test whether the Set has the ID:
if(!ids.has(displayId)) {
oTable.fnDeleteRow(idx);
}
});
So now the time complexity is not any more O(n.m) -- where n is number of messages, and m the number of table rows -- but O(n+m), which for large values of n and m can make quite a difference.
Notes:
If theCurrentTable is not a true Array, then you might need to use a for loop like you did, or else use Array.from(theCurrentTable, function ...)
Secondly, the implementation of oTable.fnDeleteRow might be that you need to delete the last rows first, so that idx still points to the original row number. In that case you should reverse the loop, starting from the end.

Better way to create arrays in javascript?

I'm trying to create an array in Javascript with a size that is equivalent to the number of times a certain class is found in the DOM, and then iterate through it to grab the text from an input field present in that class. I can easily do this like so:
var count = 0;
$('.className').each(function() {
count++;
});
var classes = new Array(count);
count = 0;
$('.className input[type=text]').each(function() {
classes[count++] = $(this).val();
});
This looks like a lot of code for what seems to be a relatively simple task. Is there a more efficient or less lengthy way of doing this?
Thanks
It looks like you want this :
var classes = $('.className input[type=text]').map(function(){
return this.value
}).get();
But it's a guess : it's not clear why you start by counting all elements of the class and then iterate on the inputs.
You can construct an array of elements directly from your selector via the makeArray function, then transform the result using a map.
var classes = $.makeArray($('.className input[type=text]')).map(function() {
return $(this).val();
});
Use jQuery's map function, then get if you need a pure array:
var values = $('.className input[type=text]').map(function() {
return $(this).val();
}).get();
each passes the index, so you don't need to do it yourself:
var classes = [];
$('.className input[type=text]').each(function(index, value) {
classes[index] = $(this).val();
});
Arrays are dynamic and therefore don't need to be initialized. Create a new array, loop through the inputs and push the values to the new array:
var classes = [];
$('.className input[type=text]').each(function(idx, elem) {
classes.push($(elem).val());
});

jQuery .each help, I want to trim() all the strings in an array

I'm splitting a string into an array, then I want to remove the white space around each element. I'm using jQuery. I'm able to do this successfully with 2 arrays but I know it's not correct. How do I loop thru an array and trim each element so the elements keep that change. Thanks for any tips. Here is my working code using two array. Please show me the correct way to do this.
var arVeh = vehicleText.split("|");
var cleanArry = new Array();
$.each(arVeh, function (idx, val) {
cleanArry.push($.trim(this));
});
Cheers,
~ck in San Diego
You don't even really need the idx or val parameters. This appears to work on jsFiddle:
var cleanVehicles = [];
$.each(vehicleText.split("|"), function(){
cleanVehicles.push($.trim(this));
});
EDIT: Now that I've seen what you're really after, try using map:
var cleanVehicles = $.map(vehicleText.split("|"), $.trim);
I'm going to suggest not using the overhead of jQuery for a simple for-loop...
var arVeh = vehicleText.split("|");
for (var i = 0, l = arVeh.length; i < l; ++i) {
arVeh[i] = $.trim(arVeh[i]);
});
Alternatively, get rid of the whitespace from the beginning, and avoid the need for another loop at all.
var arVeh = $.trim(vehicleText).split(/\s*\|\s*/);
Without 'creating' an array in the javascript code (an array will nevertheless be created in memory)
vehicles = $.map(vehicleText.split("|"), function(e,i) { return $.trim(e) });
var my_arr = [' cats', 'dogs ', ' what '];
$.each(my_arr, function (id, val) {
my_arr[id] = $.trim(val);
});
console.log(my_arr);
This will trim the value and set it to the indexed item.
You don't have to use JQuery. Here is your vanilla solution:
testArray.map(Function.prototype.call, String.prototype.trim);
Function.prototype.call calls trim() on each of the elements of the testArray. As simple as that!
Could you not just do this?
var arVeh = vehicleText.split("|");
$.each(arVeh, function (idx, val) {
arVeh[idx] = $.trim(this);
});
//a simple function
function trimArray(dirtyArray){
$.map(dirtyArray.split("|"), function(idx, val){
return $.trim(this);
});
}
trimArray(vehicleArray);
should do the trick
Or you could use some of the awesome power of javascript and use array.prototype. I'm still a little new at using the .prototype of any object... so this isnt guaranteed to work (but it certainly can be done).
Array.prototype.trim = function (){
$.map(dirtyArray.split("|"), function(idx, val){
return $.trim(this);
});
}
someArray.trim()
You need these two jQuery functions:
1.) iterate through array element with ability to edit items:
http://api.jquery.com/jquery.map/
2.) remove blank spaces from beginning and end of a string:
http://api.jquery.com/jQuery.trim/
Use them this way:
array = $.map(array, function(value) { return value.trim();});
Check this JSFiddle:
https://jsfiddle.net/L00eyL4x/49/

Remove an element from find return

With the fallowing code I want to delete the last element inside the steps variable,
var steps = $(element).find("fieldset");
var count = steps.size();
steps[count-1] = null;
but when I iterate with the each method, it doesn't seems to see the null value
steps.each(function(i) {
});
Use the slice function
steps = steps.slice(0, -1);
You could use not() to create a new jQuery object removing the elements you don't want:
steps = steps.not(steps.last());

Categories