Javascript vs. CSS for swapping elements - javascript

I have a rather lengthy (~100 fields) form that has certain elements which are toggled between a "quick" and a "full" quote. This toggles 75 of the fields from hidden to visible. Currently, I do this via some simple jQuery:
jQuery('.full_quote').show();
jQuery('.quick_quote').hide();
I realized that this could be accomplished in a different way using CSS to do the work for me:
## Javascript:
jQuery('#quote_form').toggleClass("full_quote quick_quote");
## CSS:
form.toggle-form.full_quote .quick_quote {display: none;}
form.toggle-form.quick_quote .full_quote {display: none;}
So the bulk of the question is: Which is better to use when performance is concerned?
My initial thought is that the overhead of iterating over the results in jQuery will take more time than the CSS. I do not have a way to test this, however, so I'm curious the community's experience.

Rather than defining new custom classes, or using jQuery's show and hide methods, I'd actually advise a third option.
Add a [hidden] attribute to whatever element needs to be hidden, and remove the attribute when it needs to be shown:
JS:
$('.foo').attr('hidden', true);
To make sure that this is supported cross browser, you'll need to add a bit of CSS:
CSS:
[hidden] {
display: none !important;
visibility: hidden !important;
}
This also gives you the ability to override how "hidden" elements are styled, which can be useful for debugging.
When you want to show the element, simply remove the [hidden] attribute:
JS:
$('.foo').attr('hidden', false);
It would be nice if jQuery implemented show and hide to utilize [hidden], instead developers need to take care when using show as it will override any stylesheet declarations for display when it adds a display style inline.

Both are essentially the same. JQuery does a very similar the same logic internally. (See How does jquery's show/hide function work?). And it is not like your CSS apprach does not use javascript at all (in that case, it would be the better option)
So,
jQuery('.full_quote').show();
jQuery('.quick_quote').hide();
makes sense (you are using JQuery anyway, why not use all of its functions) s a lot more readable, and

Related

jQuery's show/hide won't work with elements not attached to DOM (breaking change found in 3.0)

I am working on upgrading big application to latest jQuery 3.0 from pretty ancient 1.11.2. I found pretty subtle change that broke some of our functionality:
when we instantiate some complex widgets, we initially hide some of the elements using css (display none). Then we use show/hide to display the element.
But call to show/hide can happen before widget is attached to DOM. Show/hide used to work fine in 1.11.2 when element was not attached, but does not work in 3.0.0.
Demo:
1.11.2: https://jsfiddle.net/7j9xawc2/1/
3.0.0: https://jsfiddle.net/vma214mL/1/
.tabCompositeSearchWidget-ClearButton
{
/* Clear button is initially hidden */
display: none;
}
var e = document.createElement('div');
$(e).addClass('tabCompositeSearchWidget-ClearButton');
$(e).text('blah');
$(e).show();
$('#root').append($(e));
alert($(e).is(":visible"));
In the old version element will be visible and alert will say true, in the most recent it won't be visible and alert will say false
It is hard to find all of such usages and I am interested in the best way of fixing that:
what can be the best fix here? Manually modifying jquery.js file to behave it the old way? (I don't really want to do that)
Upd: fixing one-off case is easy. But have potentially tens of such calls and finding & fixing all of them needs huge effort and is not effective.
Here's the relevant section from the jquery blog:
"If you have elements in a stylesheet that are set to display: none, the .show() method will no longer override that. So the most important rule for moving to jQuery 3.0 is this: Don’t use a stylesheet to set the default of display: none and then try to use .show() – or any method that shows elements, such as .slideDown() and .fadeIn() – to make it visible.
If you need an element to be hidden by default, the best way is to add a class name like “hidden” to the element and define that class to be display: none in a stylesheet. Then you can add or remove that class using jQuery’s .addClass() and .removeClass() methods to control visibility. Alternately, you can have a .ready() handler call .hide() on the elements before they are displayed on the page. Or, if you really must retain the stylesheet default, you can use .css("display", "block") (or the appropriate display value) to override the stylesheet."
https://blog.jquery.com/2015/07/13/jquery-3-0-and-jquery-compat-3-0-alpha-versions-released/
try $('div') instead var e = document.createElement('div');

Select only (display:block) element from list of items Jquery

I'm making a menu and i need to select one particular element from a list of element returned by Jquery.
When i run on console :
$("[type='subMenu']")
This returns 4 matching submenu elements.
<div type="subMenu" style="display:block">
<div type="subMenu" style="display:none">
<div type="subMenu" style="display:none">
Now, i need to select only the element having display:block
I tried
$("[type='subMenu']").css('display') == 'block'
but this give false as output.
and
$("[type='subMenu']").css('display')
this is giving output as none
Others have already pointed out the JQuery :visible selector. However, there are some performance issues with it, as pointed out in the JQuery API documentation:
Additional Notes:
Because :visible is a jQuery extension and not part of the CSS specification, queries using :visible cannot take advantage of the performance boost provided by the native DOM querySelectorAll() method. To achieve the best performance when using :visible to select elements, first select the elements using a pure CSS selector, then use .filter(":visible").
Using this selector heavily can have performance implications, as it may force the browser to re-render the page before it can determine visibility. Tracking the visibility of elements via other methods, using a class for example, can provide better performance.
If you'd prefer to avoid those issues, you could use a native CSS selector, instead. In plain ol' normal JavaScript, this would do the trick for you:
document.querySelector("[type=subMenu][style*=display\\:block]");
Or, if you need to select multiple elements at once:
document.querySelectorAll("[type=subMenu][style*=display\\:block]");
I believe the equivalent in JQuery (I don't use it) for both would be:
$("[type=subMenu][style*=display\\:block]");
If the only style that will ever be set inline on those tags is display then you can omit the * from the style attribute selector.
Try this:
console.log($("[type='subMenu']:visible")).
It will give all visible elements
You can use filter or pseudo class.
$("[type='subMenu']").filter(function(){
this.style.display == 'block';
});

Difference between using hide, prop, attr or css to hide an element with JQuery

I have set up 4 divs to test the different results of using:
$("#div1").hide();
$("#div2").prop("hidden", true);
$("#div3").css("display","none");
$("#div4").attr("hidden", true);
I can see that the result is (I am using version 1.11.3):
<div id="div1" style="display: none;">Something</div>
<div id="div2" hidden="">Something</div>
<div id="div3" style="display: none;">Something</div>
<div id="div4" hidden="hidden">Something</div>
It seems kind of confusing to me to have four different ways of achieving pretty much the same result. I have seen some explanation in .hide() or display: none? jQuery but I wonder if someone can provide more information and mainly, when should I use which??
//this is a wrapper function. simply adds display none inline. for ease of use
$("#div1").hide();
//prop is used to manipulate any property on the object. hidden is a property. so it doesn't stop you from doing it.
$("#div2").prop("hidden", true);
//css is a wrapper for the style attribute. display is a valid css property so it won't stop it
$("#div3").css("display","none");
//this one seems odd. i thought it would be hidden="hidden" but anyway. attr() is used to change the attributes on the markup. hidden is a valid attribute so it doesn't stop you
$("#div4").attr("hidden", true);
It's all about your style of coding. If they all work, you get to use the one that you like best. Just try to be consistent if possible, imho.
There sure is a difference, but I'm not going to cover them all.
A real life story:
I just had a project, in which I needed to filter DOM elements by their display property.
Same DOM elements was set to 'none', by using .hide() and shown by setting .show()
This usage, while short and neat, made problems filtering by display property, as it always showed 'none' in a console output. Even if the element list showed 'block'.
So a caching occours using .hide()
You don't just wanna use whatever you like best. Only if you like best what works for your specific needs ;)

Removing effect of a CSS selector

My requirement is a bit tricky. I have a mark-up as below: (just an example, real mark-up is very complicated)
<div class="classA">
<div class="classB">
<p class="classC">
<span class="classD">
</span>
</p>
</div>
</div>
As you can see above, there are four CSS classes classA, classB, classC, classD associated with the markup.
Also I have used jQuery to bind events using these selectors.
My Requirement: I want the jQuery event binding to work and at the same time, the CSS should not get applied i.e. I want to negate the impact of CSS styles from a UI perspective, but from functional perspective jQuery event handlers should still work.
So, is it possible to override the CSS selectors such that their styles don't get applied to my mark-up elements ?
example below:
div.classA div.classB p.classC span.classD{
color:red;
}
I don't want the font color to be red, so I tried to override the selector as follows, but its not working:
div.classA div.classB p.classC span.classD{
color:red;
}
div.classA div.classB p.classC span.classD{
/*no styles here*/
}
Please help !!
Then just delete those classes from css. jQuery will still work though.
There is no requirement that only classes used in css have to be used in jquery.
For example:
<div class="someUnknownClass"></div>
Even though, there is no someUnknownClass defined in css, $('.someUnknownClass') will still work.
Use another class name for the selector. So you have classA for the css and classX for the selector.
If you don't want the styles applied. Then you could use $('selctor').css(); to over write the styles. Bit hacky!
OR.
Add a class that over-rides the css. Or remove the class that holds the css.
using: $('selctor').addClass('no_styles'); OR $('selctor').removeClass('current_styles');
I don't know any mechanism allowing to do that the way you want it.
the work around i would suggest would be binding your events on anoter css class and doing something like this :
$('.classD').addClass('eventClassD').removeClass('classD');
$('.eventClassD').on('myEvent', function(){...});
like this you will still have events binded to your elements and would get rid of all the css.
You want to do it without modifying the JS? There's no clean way to do that. But try this.
Presumably you will have something that distinguishes this special set of elements to distinguish it from other elements, of which styles' you want to retain. This is difference probably manifests itself in the form of a different parent container. Just copy the set of CSS rules that affect these classes, and prepend this parent CSS selector with the pre-class values.
"Basically, I do not want to touch the js code, and only if something can be done on the css front, then my requirement is achieved."
If that is all you need, then just remove all of the css definitions from the page.
$("link,style").remove()

Modify dynamically created jQuery checkbox button's css

I'm creating a series of jQuery checkboxes in a loop like so:
var checkbox = $('<input>').attr({type: 'checkbox', id: checkbox_id);
panel.append(checkbox);
panel.append($('<label>').attr({for: checkbox_id}).html(checkbox_name);
checkbox.button();
I have a css class called my-style that defines things like border-radius, padding, and line-height. I want my-style to override the attributes defined by jQuery's theme for only the checkboxes I've created.
I tried checkbox.addClass("my-style"); and panel.find(".ui-button-text").addClass("my-style"), but neither works correctly. Some css attributes do overwrite jQuery's default values, like border-radius, and others don't ever seem to be able to be overwritten like line-height and padding. I even tried to enforce css attributes directly by panel.find(".ui-button-text").css("line-height", 1.0);, but that doesn't work at all.
I understand that I could just modify the jQuery theme directly by changing the css code in there, but doing so would affect all buttons made, which is not what I'd like to do.
UPDATE:
One way I've managed to address this issue is by specifying the style tag directly. So the code above becomes:
var checkbox = $('<input>').attr({type: 'checkbox',
id: checkbox_id});
panel.append(checkbox);
var label = $('<label>').attr({for: checkbox_id,
style: "font-size: 0.6em; border-radius: 0px; margin-right: 0.3em;"}).text(checkbox_name);
panel.append(label);
checkbox.button();
label.children().attr("style", "padding: 0.2em 0.4em;");
While this solution works, it's unsavory, as I'm mixing JavaScript and CSS code together.
By writing in the style attribute, I can override jQuery UI's CSS. One thing that's been discussed here is using more specific CSS selectors that will be given more weight than jQuery UI's CSS classes. A more specific selector would be something that has the checkbox's ID. The problem with this approach is that checkboxes are dynamically generated, and thus so are checkbox IDs. It's therefore not feasible to have more specific CSS selectors from what I understand.
Is the problem that the class isn't getting applied to the element, or that the class isn't doing what you want it to do?
If the latter, can you paste the css code for your class?
It sounds like your CSS selector is not specific enough, you have two options here
Be nasty and declare your CSS properties with !important to override anything else selected
Write a more specific CSS selector
The latter is the better option, as you will have more control over your styling at a later stage. In case you don't know much about CSS selectors take a read of this (http://www.stuffandnonsense.co.uk/archives/css_specificity_wars.html) which should help understand writing more specific selectors and the value of each selector type.

Categories