jQuery append issue without removing original elements - javascript

I just wrote some code for practicing my jQuery. When I wrote this code, I found out it works fine with only using append() and without removing any original tr elements in the table. How does it work — could someone explain it to me? here is the complete code. Thanks!
Here is my jQuery code:
$(document).ready(function () {
var list = a();
var last = $('#table').find("tr").length;
$('#table').find("tr").each(function (index, element) {
$(this).prepend($("<button/>").text("↑").bind('click', function () {
up($(this).parent(), last);
}));
$(this).prepend($("<button/>").text("↓").bind('click', function () {
down($(this).parent(), last);
}));
});
$('#table').before($('<button />').text("reset").on('click', function () {
reset(list);
}));
});
function up(tr, last) {
if (0 != tr.index()) {
var prevTr = tr.prev();
tr.after(prevTr);
}
}
function down(tr, last) {
if (last - 1 != tr.index()) {
var nextTr = tr.next();
tr.before(nextTr);
}
}
var reset = function (list) {
for (var i = 0; i < list.length; i++) {
$("#table").append(list[i]);
}
};
var a = function () {
var list = [];
$('#table tr').each(function () {
list.push($(this));
});
return list;
};

Be aware, appending already existing element just move it. I guess maybe you want to clone it:
jsFiddle
var reset = function (list) {
for (var i = 0; i < list.length; i++) {
$("#table").append(list[i].clone(true));
}
};
But then, reset function is misnamed...

$(document).ready(function () {
waits for the page and all elements to be loaded
var list = a();
var last = $('#table').find("tr").length;
sets up specific variables, in this case list is the function a() defined later in the page and last gets the length of the last tr in the table.
$('#table').find("tr").each(function (index, element) {
sets up a loop through each tr element on in the table with id #table
$(this).prepend($("<button/>").text("↑").bind('click', function () {
up($(this).parent(), last);
}));
Because you are inside the loop, $(this) represents the tr that the loop is currently on. It then prepends a button and adds a click listener on this button. When the button is pressed, it will call the function up, which is defined later on, with the buttons parent as the first parameter and last (defined earlier) as the second
$(this).prepend($("<button/>").text("↓").bind('click', function () {
down($(this).parent(), last);
}));
This adds another button, but calls down() instead of up()
});
End of the loop.
$('#table').before($('<button />').text("reset").on('click', function () {
reset(list);
}));
This adds a button before the table that when clicked calls the reset function with list as the only parameter, list is set to a().
});
function up(tr, last) {
if (0 != tr.index()) {
var prevTr = tr.prev();
tr.after(prevTr);
}
}
This function is called when moving an item up, it first checks to see if the index is not 0 (so not the first element as this couldn't be moved up) if it is not then it puts the previous tr after the variable tr. Which in this case is the parent to the button (or the current tr)
function down(tr, last) {
if (last - 1 != tr.index()) {
var nextTr = tr.next();
tr.before(nextTr);
}
}
Works exactly the same as the function above, but in the opposite direction.
var reset = function (list) {
for (var i = 0; i < list.length; i++) {
$("#table").append(list[i]);
}
};
This function is saved in the variable reset, it loops through each tr (defined in a()) and appends it to the table,
var a = function () {
var list = [];
$('#table tr').each(function () {
list.push($(this));
});
return list;
};
This function creates and returns an array which loops through each tr and adds to that array. So we know the original state and can return to it.

Related

Is it more performant to cache a selector in a function if that function's called multiple times?

Ok I think I know the answer to this, looking to confirm. So I have a selector that's only used once, but it's used inside a function that's called several times. From a performance perspective, since that selector is re-searched-for each time the function is called, it's probably (albeit marginally) better to cache the selector?
In other words, the below...
function testFunction() {
alert($("#input").val())
}
$("#a").click(function() {
testFunction()
})
$("#b").click(function() {
testFunction()
})
$("#c").click(function() {
testFunction()
})
...is not as performant as the below
input = $("#input")
function testFunction() {
alert(input.val())
}
$("#a").click(function() {
testFunction()
})
$("#b").click(function() {
testFunction()
})
$("#c").click(function() {
testFunction()
})
Evidently, jQuery() call completes in less total time than variable reference to jQuery object. Last run logged
jQuery(): 16.580ms
cached jQuery() object: 22.885ms
(function() {
function testFunction() {
$("#input").val()
}
console.time("jQuery()");
for (let i = 0; i < 10000; i++) {
testFunction()
}
console.timeEnd("jQuery()");
})();
(function() {
let input = $("input");
function testFunction() {
input.val()
}
console.time("cached jQuery() object");
for (let i = 0; i < 10000; i++) {
testFunction()
}
console.timeEnd("cached jQuery() object");
})();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<input>
Yes you are right the second one is more efficient than the first one because
In the first one to select the input filled first it going to find the input
field then it select that input field,And this will happen each time of function call.
But in second case the selector is select once when the page is loaded the it refers that selector through the variable and will not go to find that input field in each call.That why 2nd one is more efficiency.
<input value='Value' id='input'><br>
<span id='tt'>dssd</span><br>
<span id='t1'></span><br>
<span id='t2'></span>
And Jquery:-
function testFunction1() {
var t=$("#input").val()
$("#tt").html(t);
}
console.time("jQuery() object");
var t1=performance.now();
for (var i = 0; i < 50000; i++) {
testFunction1()
}
console.timeEnd("jQuery() object");
var t2=performance.now();
t2=t2-t1;
$("#t1").html('Without selector variable:- '+t2);
var input = $("input");
function testFunction2() {
var t=input.val();
$("#tt").html(t);
}
t1=performance.now();
console.time("cached jQuery() object");
for (var i = 0; i < 50000; i++) {
testFunction2()
}
t2=performance.now();
console.timeEnd("cached jQuery() object");
t2=t2-t1;
$("#t2").html('With selector variable:- '+t2);
Just Check here:-click here

How can I pass a function reference with multiple arguments to the callback of my jQuery(document).on('click' event?

I have the following code definition
$(document).on('click', firstRow, processEvent(firstRow, rowArray));
Which uses the parameters below. As it currently stands I am passing the function processEvent rather than the function definition stored in the variable, and so the function is being invoked immediately.
I wish to set up click handlers dynamically, and for my feature to work I need to be able to pass two parameters to the callback on the click event. The first is a reference to the DOM element(s) the click is attached to, and the second is an array of DOM elements indentifiers (stored as strings) .
How can I pass a function reference with multiple arguments to the callback of my jQuery(document).on('click' event?
var firstRow = '.first-row';
var secondRow = '.second-row';
var thirdRow = '.third-row';
var rowArray = [firstRow, secondRow, thirdRow];
var hideRow = function(input){
var Input = input;
$(Input).show();
};
var showRow = function(input){
var Input = input;
$(Input).hide();
}
// alert(rowArray);
//Hide second and third rows
$('.second-row, .third-row').hide();
var processEvent = function(e, fooArray){ // currently set to one
var E = e; // Cache ID of calling object
var a = fooArray;
// alert(E);
// alert(a);
var arrayLength = a.length;
for (var i = 0; i < arrayLength; i++) {
foo = a[i];
// alert(row); //
alert(foo);
if (foo = e){
showRow(e);
}
else {
hideRow(foo);
}
}
} // function testProcessEvent(){ processEvent(); }
$(document).on('click', firstRow, processEvent(firstRow, rowArray));
This is my first attempt
$(document).on('click', firstRow , someFunction(firstRow ));
Use
$(document).on('click', firstRow, function () {
//place the code here
processEvent(firstRow, rowArray);
});

Get string to array with multiple .each function

I have two elements and will get strings inside. (and i use .each` function)
The problem is that the second array (after got string by .each), is replace the first one.
Sorry, if you don't understand, but try to look below...
$('div').each(function () {
var data = [];
$('li', this).each(function () {
data.push($(this).text());
});
var data_length = data.length;
$(this).children("code").html(data + "");
$("code").click(function () {
data.move(data_length - 1, 0);
$(this).html(data + "");
});
});
Array.prototype.move = function (old_index, new_index) {
if (new_index >= this.length) {
var k = new_index - this.length;
while ((k--) + 1) {
this.push(undefined);
}
}
this.splice(new_index, 0, this.splice(old_index, 1)[0]);
return this; // for testing purposes
};
Demo: http://jsfiddle.net/kdpN7/
What did I do wrong?
For the same reason you do $(this).children('code') you should also bind your click event with a scope.
The problem is, you're iterating over 2 divs (your each) which means you're binding $('code') twice. The first time code is bound to click, it binds with the first data array (the 1's) and then it is bound a second time with (the 2's). So it IS first doing your click code for the 1s and then immediately running it for the 2s, thus overwriting. Change to $(this).find("code") (or children) and it works as expected.
http://jsfiddle.net/kdpN7/1/
On this line:
$("code").click(function () { ...
This is telling to update all code with that information. You need to change it so it's specific to each div:
$(this).find("code").click(function () { ...
Updated fiddle: http://jsfiddle.net/kdpN7/2/

Loop through js array continually with pauses

I want to loop over an array continuously on click. Extra props if you can work in a delay between class switches :-)
I got this far:
// Define word
var text = "textthing";
// Define canvas
var canvas = 'section';
// Split word into parts
text.split();
// Loop over text
$(canvas).click(function() {
$.each(text, function(key, val) {
$(canvas).removeAttr('class').addClass(val);
});
});
Which is not too far at all :-)
Any tips?
The following will wait until you click the selected element(s) in the var el. In this example var el = $('section') will select all <section>...</section> elements in your document.
Then it will start cycling through the values in cssClassNames, using each, in turn as the css class name on the selected element(s). A delay of delayInMillis will be used between each class change.
var cssClassNames = ['c1', 'c2', 'c3'];
var el = $('section');
var delayInMillis = 1000;
// Loop over text
el.click(function() {
var i = 0;
function f() {
if( i >= cssClassNames.length ) {
i = 0;
}
var currentClass = cssClassNames[i];
i += 1;
el.removeClass().addClass(currentClass);
setTimeout(f, delayInMillis);
}
f();
});
I believe you want a delay of X milliseconds between removing a class and adding a class. I'm not sure that you have to have the lines marked // ? or even that they do the job, but what you do have to have is a way to get the value's into the function. Also, the setTimeout anon function might not actually need the parameters, but it should give you an idea.
$(canvas).click(function() {
$.each(text, function(key, val) {
$(canvas).removeAttr('class')
var $canvas = $(canvas) //?
var class_val = val //?
setTimeout(function ($canvas, class_val) {
$canvas.addClass(class_val);
}, 2000);
});
});
Edit: I'd do this instead
function modify_element($element, class_name){
$element.removeClass('class');
setTimeout(function ($element) {
$element.addClass(class_name);
}, 1000);
//adds the class 1 second after removing it
}
$(canvas).click(function() {
$.each(text, function(key, val) {
setTimeout(modify_element($(canvas), val),2000);
//this will loop over the elements with 2 seconds between elements
});
});
"loop over an array continuously" this sounds like a infinite loop, I don't think you want that. About pausing the loop, this is possible, you can use this

Duplicating JQuery/Javascript functions

I have a jquery/javascript function that creates an array to be placed in a form's hidden field. However, this is a nested form and so I need to invoke this function many times to populate the hidden field for all the children: test_suite_run[test_runs_attributes][//id][packages_id]. This means that I need to run this function with a different child id each time.
I have added //id to indicate the only differences between the many function calls. I do not know how to duplicate this function without copying it many times manually and replacing //id with the indexes 0...n, for each nested child instance. Could this somehow be done by passing parameters to the javascript function?
Sorry if this a little confusing, I will be happy to explain in more detail if needed.
JQuery Function
$(document).ready(function () {
arr = new Array();
$(document).on('change', 'select[id ^="s_package//id"]', function () {
var arr = $('select[id ^="s_package//id"]').map(function () {
return this.value
})
result = ""
for (j = 0; j < arr.length - 1; j++) {
result += (arr[j] + ", ");
}
result += (arr[arr.length - 1])
$("input[name='test_suite_run[test_runs_attributes][//id][packages_id]']").val(result);
});
});
You can pass an array of ids to use in your function and iterate them:
function somethingMeaningful(ids) {
for (var i = 0, l = ids.length; i < l; i++) {
var id = ids[i];
// do something with this id
}
}
$(function() {
somethingMeaningful(['id1', 'id2', 'idn']);
});
It might also be possible to simplify your selector and calculate the id at runtime, depending on their actual format:
$(document).on('change', 'select[id^="s_package"]', function () {
var id = $(this).attr('id').slice('s_package'.length);
// Do stuff with real id
});

Categories

Resources