Slow performance with jQuery selector - javascript

I'm rendering over 600 forms in an MVC format (php Codeigniter). Each one of these forms has a button labeled "More Options". When you click this button - a hidden div, located in the same parent element, is toggled, displaying more input fields and data. The problem is that the sibling toggle is quick in console, but when I click the actual button, it takes very long to trigger.
Using id's is the recommended fix, but it is slightly impractical when I have this many div elements to go through.
Here is my js file
jQuery(document.ready(function(){
jQuery("form >button[name='more_data'].meta_button").click( function(){
jQuery(this).siblings("div.meta").toggle("fast");
});
});
Here is the structure (there are 650 of these div's, with more to come)
<div>
<li id="bCIya8DZyr4idseJe5cbLA" class="even">
<form action="url" method="post" accept-charset="utf-8">
<div class="space_name"></div>
<button name="more_data" type="button" class="meta_button">More Options</button>
<input type="submit" name="Submit" value="Submit">
<div class="meta" style="overflow: hidden; display: block;">
<div class="meta_block">Set Estimates:
<div class="input_estimate">1:
<input type="number" name="estimate_1" value="" id="estimate_1" class="estimate">
</div>
<div class="input_estimate">2:
<input type="number" name="estimate_2" value="" id="estimate_2" class="estimate">
</div>
<div class="input_estimate">3:
<input type="number" name="estimate_3" value="" id="estimate_3" class="estimate">
</div>
</div>
</div>
</form>
</li>
</div>
Note: I'm running jQuery 1.7.2

Don't use a delegate
Using a delegate (.on() with a selector) like #jrummell suggested is faster when you have multiple event listeners, because you reduce the number of listeners to one.
Simpler selector using a class
So in this case though I would recommend using a simpler selector:
$(function(){
$('.meta_button').on('click', function(){
$(this).siblings('div.meta').toggle('fast');
});
});
This way you have quite simpler selector and less checks when a click is triggered, because there is no delegate. Also the clicks on other elements in the forms are not captured.
Animations slow things down
An animation could slow things down. An animation which is performed over multiple elements simultaneously even more.
Try moving all div.meta elements in a single parent and applying animation only on that single element.
You could also remove the animation entirely by just using toggle() (the comment about the multiple items is still valid in this case).
Example:
$(function(){
$('.meta_button').on('click', function(){
$(this).parent().find('.meta_holder').toggle();
// OR
// $(this).next('.meta_holder').toggle();
});
});

Including jQuery.ui.css made the redisplay incredibly slow. Costly css rules killed the display and slowed down rendering times. The "nudge in the right direction" is in the comments of the question.

Related

I need a clarification of targeting an element from the markup

I am following a class online and the tutor target a <button> document in which I don't really understand how he did it because he used a document.querySelector to target the parent and that's all.
<div class="row">
<form id="task-form" action="index.php">
<div class="input-field col s12">
<input type="text" name="task" id="task" value="">
<label for="task">New Task</label>
</div>
</div>
<button id="add" class="btn">Add</button>
</form>
he then wrote :
document.querySelector('form').addEventListener('submit', function(event) { /* ... */ })
to me what I understand is that the querySelector will only select the firstChild in this case.
The code just targets the <form> and adds a listener for the submit event.
It is not targeting any <button>.
He actually doesn't add listeners to any button. What you confused was the <form> having an onsubmit event listener. Since there is only one button in the form, its type attribute is automatically set to submit, making it trigger the form.onsubmit event every time.
Also, the code is a bit wrong. You open a div, a form, and before closing the form, you close the div. If that was made by the person who runs the course, I would recommend to stop watching that course in general, since it can confuse a lot...

duplicate div containing set of fields in the same dom

i am loading handlebar templates in the two div locations(like add and edit tabs both are jsps) from the same page. so i have duplicate elements in the DOM object, since it is a template which is coming from server location. you can see the sample code below
<div id="add">
<div id="exploding">
<input type="text" name="city" id="city"/>
<input type="text" name="state" id="state"/>
...
</div>
</div>
<div id="edit">
<div id="exploding">
<input type="text" name="city" id="city"/>
<input type="text" name="state" id="state"/>
...
</div>
</div>
I can't modify the div container ids i.e exploding since some javascript functions attached to it based on that id to explode address field.
here the problem is if i made any changes to the edit tab, address "exploding" div, it is effecting in add tab address "exploding" since ids are repeated. i have tried jquery detach method to remove the dom elements, but didn't get proper result. Its a web application based on spring boot.
is there any possibility to load jsps dynamically through jquery, i have tried load method as well, but the call is going through controller. I didn't feel it as better option.
Thanks & Regards
krishna K

Disable click in input in <a> element

I would like to have an input text inside a button like this:
<a onclick="reply_click();" class="btn btn-app btn-app-spinner">
<input type="text" disabled class="form-control small-input">
Set Budget
</a>
this is the result:
The problem is that when the user clicks on the input text, the reply_click() is triggered. I would it to be triggered ONLY when he clicks on the a element (Set Bid).
How can I do it?
See jsfiddle
EDITED
As you can see I want to make it look similar to the buttons in the design as you can see in the JSfiddle
Putting an input inside an a element is invalid HTML. From the spec for a:
Content model:
Transparent, but there must be no interactive content descendant.
input is interactive content, so it cannot appear within an a. Browsers may well choose to rewrite your HTML to put the input after the a to try to make it valid.
So the solution here is not to put an input inside an a. Not only because HTML doesn't allow it (you could work around that with a click handler on a div), but because it's extremely unusual UX, which will be unfamiliar and likely uncomfortable to users.
Having said that, if a browser doesn't relocate the input (or if you replace the a with a div with click handler), you can stop the event from propagating to the a by hooking click on the input and using stopPropgation:
$("a input").on("click", function(e) {
e.stopPropagation();
}):
I'm not recommending it, though.
In theory you can achieve the effect you're looking for with something like this
$(".setBid").click(function(e){
var $input = $(this).find("input[type='text']");
if ($input.is(e.target)
{
//do action
}
})
here's the html
<a class="btn btn-app btn-app-spinner setBid">
<input type="text" disabled class="form-control small-input">
Set Budget
</a>
however, as #TJ said this is NOT valid HTML
This is invalid html! don't do that!
If you must, then just stop propagation by handling a click on the input:
function reply_click(e){
alert("clicked!");
}
function input_click(e)
{
e.stopPropagation();
return false;
}
<a onclick="reply_click();" class="btn btn-app btn-app-spinner">
<input type="text" class="form-control small-input" onclick="input_click(event)">
Set Budget
</a>
This snippet is not cross-browser safe (tested in chrome). Use jQuery, or handle the way other browsers deal with events.
you can do this:
<div class="btn btn-app btn-app-spinner">
<input type="text" class="form-control small-input">
<a onclick="reply_click();" >
Set Budget
</a>
</div>
In your fiddle replace your html with the html that I provide on the answer and you will have what you want.
The trick is that adding the same classes that you have in your a to another element they are going to look like similar.
Then if you want your action fired when user clicks on the "set budget", wrap it with the <a>
You can create a div and use the click on that div. That way you have valid HTML.
function bid(){
alert('bid');
}
function stop(e){
e.stopPropagation();
}
div {
width:200px;
height:60px;
background-color:#f93;
text-align:center;
padding-top:20px;
}
<div onclick="bid()">
<input type='text' onclick="stop(event)">
<p>bid</p>
</div>
You should not wrap the input element inside a link.
Instead, the input needs a label (for accessibility, especially screen reader users) and something that functions as a button (a real button element in the code below). Since you don't have a proper label element, I used WAI-ARIA described-by to link the input field with the button.
<form>
<input type="text" class="form-control small-input"
aria-describedby="ses-budget" />
<br />
<button type="submit" onclick="reply_click();"
class="btn btn-app btn-app-spinner" id="set-budget">Set budget</button>
</form>

Javascript get similar elements without jQuery

i have something like this :
<li id="test">
<input type="text" name="firstname" />
</li>
<li id="test2">
<div id="special">
<input type="text" name="city" />
<input type="text" name="pc" />
</div>
</li>
When a user clicks on one input, I'd like to get all lis with an input child. For example, if a user clicks on .pc, I'd like to return both #test and #test2. I cannot use jQuery or any other external libraries.
for the second one (test2 in pc), you could use
$('#pc').closest('li');
to grab the closest parent of type li. (this would return just test2)
If you want both, however, you could give them a unique class (or something to help pick them out), and you could use
$('#pc').parents('li.myclass');
as an example
Edit: these are assuming also that you only want these two tests. If you want all of the li's, you could just use
$('#pc').parents('li');
Edit2: If it is not possible to use JQuery, there is a method someone wrote to handle this here
There is a reason jQuery is around...
You could start with looping over document.getElementsByTagName('li') then loop through the children, looking for an element with a tagName === 'INPUT' and then loop through the children's children etc.
Or go the other way checking parent from all inputs as in this answer -> How to check in Javascript if one element is contained within another

Is there a maximum number of elements I can bind a jquery event to?

I'm building a simple 1 page app that allows someone to curate a list of json feeds. I'm running into an issue with trying to bind a mouseenter/mouseleave event to all the inputs on the page with a given class. Simply, put the first works and the second does not.
I have to following jquery:
$(".feed").on("mouseenter", ".publish", function(){
console.log("feed")
}); //this is for test purposes
$(".feed").on("mouseenter", ".keys-input", function(){
console.log($(this));
$(this).siblings(".delete").fadeIn(75);
});
$(".feed").on("mouseleave", ".keys-input", function(){
$(this).siblings(".delete").fadeOut(75);
});
and the following html:
<div class="feed"><!-- sorry for the confusion -->
<div class="feed-header">
<h2>pga-2013.json</h2>
<button class="publish button-white-bg button-save">Publish</button>
</div>
<div class="kvRow collapsed">
<span class="delete icon">x</span>
<input type="text" class="keys-input" value="free" disabled=""/>
<input type="text" class="values-input" value="0" disabled=""/>
</div>
</div>
The reason I ask if there is a max number of elements you can bind to is because the ".feed" event triggers and there are only 11 of them on the dom whereas the ".keys-input" event does not and there are 7266 of them on the dom. Either that or I'm blind and doing something dumb...
here's a fiddle with fewer elements but the same code that works http://jsfiddle.net/khLPc/
this is the issue: Event on a disabled input the inputs are disabled so they won't fire events which is bananas to me...
The event is not triggered on the disabled element.
Enable the input and it will work.
Check here, I've enabled one of the input fields:
http://jsfiddle.net/balintbako/khLPc/1
Apparently I have to include some code too:
<input type="text" class="keys-input" value="free"/>

Categories

Resources