Encapsulate jQuery block for reuse - javascript

I have this jQuery code that I was originally planning to use only once, but now it turns out I have to use it on multiple instances, but I am not very familiar with code encapsulation.
So my question is, first the block:
$('.share-checklist-trigger').click(function () {
$('body').addClass('no-overflow');
$(document).scrollTop(-1);
$('.widget-top-drawer.share-checklist-drawer').slideToggle(244, "linear").dimBackground({
darkness: 0.2
});
$('.widget-top-drawer-header').slideToggle(244, "linear").attr('style', 'display: flex;');
$('.dashboard-main').addClass('top-draw-out');
}).stop();
The things that will change from object reference to another is the class after the main class .widget-top-drawer.share-checklist-drawer , e.g. - .share-checklist-drawer will be something else and the main selector e.g. - .share-checklist-trigger to something else.
How am I able to turn this into a sort of a plugin-type block, so that I can use it on multiple objects, without copy-pasting the same code over and over again?

You don't necessarily need to create an entire plugin for this. Instead you can use the common .share-checklist-trigger class to group the required elements. You can then place a data attribute on those elements to change the executed logic within the event handler. Try this:
<div class="share-checklist-trigger" data-target=".widget-top-drawer.share-checklist-drawer">Foo</div>
<div class="share-checklist-trigger" data-target=".fizz.buzz">Bar</div>
$('.share-checklist-trigger').click(function () {
var target = $(this).data('target');
$('body').addClass('no-overflow');
$(document).scrollTop(-1);
$(target).slideToggle(244, "linear").dimBackground({
darkness: 0.2
});
$('.widget-top-drawer-header').slideToggle(244, "linear").css('display', 'flex');
$('.dashboard-main').addClass('top-draw-out');
}).stop();
Also note the use of css() over setting the style directly using attr(). this could be further improved by setting the display: flex rule in a class in an external stylesheet and using addClass() in your JS code.

Related

How can I repeat Javascript expression for elements with different class names

I have multiple elements which each contain the same class name appended with a number, created dynamically depending on where in the html structure they appear, e.g. myclass-1, myclass-2, myclass-4. There could potentially (though unlikely) be unlimited class numbers.
I would like - in vanilla Javascript (no jQuery) - to add a single click function so that if the element contains any class-n except class-1 to toggle another class. I can do it individually, like this:
document.getElementById("myId").addEventListener("click", toggleClass);
function toggleClass(event){
if(event.target.classList.contains("myclass-2")){
event.target.classList.toggle("another-class");
}
}
I could repeat this code multiple times, changing "myclass-2" to "myclass-3" and so on. Is there a way to do this in one go, excluding myclass-1? N.B. I don't think it's possible to change "myclass-1" to another class name automatically on page load (or not to my limited Javascript knowledge, anyway).
If I was including "myclass-1" I could do something like this:
let existingClass = document.getElementsByClassName("*[class^=\"myclass-\"]")
But that isn't suitable here because of my need to exclude "myclass-1".
Would it be a push function? I'm very much a JS beginniner and only know the very basics of the push function, with a 'console.log' output, which doesn't help me here.
Thank you.
You can use event delegation - add a single click listener to the window. On click, if the target is a myclass and is not a myclass-1, toggle the target.
Use :not(.myclass-1) to exclude myclass-1.
window.addEventListener('click', (e) => {
if (e.target.matches('[class^="myclass"]:not(.myclass-1')) {
e.target.classList.toggle('another-class');
}
});
.another-class {
background-color: yellow;
}
<div class="myclass-1">one</div>
<div class="myclass-2">two</div>

Add class to dynamically changing element

I'm trying to use the attrchange plugin to listen to a change in one element and add a class to another element. Kind of novice to jquery and javascript and could use some help with this...
function navchange() {
document.getElementByClassName("sticky-element-cloned").addClass('shrinkwrap');
}
$(".sticky-element-original").attrchange({
trackValues: true,
callback: function (event) {
//event.attributeName - Attribute Name
//event.oldValue - Prev Value
//event.newValue - New Value
navchange();
}
});
Thanks for any insight.
Two things. Firstly, fix your DOM method to make it valid.
document.getElementsByClassName(".sticky-element-cloned")[0].classList.add("shrinkwrap");
Secondly - isn't the class sticky-element-cloned? Then why are you using sticky-element-original in your jQuery?
$(".sticky-element-cloned").attrChange({...});
Or (do one or the other, not both)
Change it in your JavaScript:
document.getElementsByClassName(".sticky-element-original")[0].classList.add("shrinkwrap");
On the navchange function you're mixing your pure Javascript with your jQuery. Try:
$(".sticky-element-cloned").addClass("shrinkwrap");

Javascript/jQuery .each and syntax issue

I'm having some trouble writing a function to change a background image on a div on document.ready
I haven't made a jsfiddle as i think the problem is just my poor (but improving) jQuery skills. Please let me know if you think one is needed.
Background Info ->
I have a collection of div's with a class of portlet-visible or portlet-hidden, each of these div's will have another class of red-arrow (or a different color, but once i have one color it should be easy to extrapolate). When the page loads i would like a function that can find all divs with a class of portlet-hidden or portlet-visible and see if those have a class of red-arrow. If they do then change the background image src to a different value.
Im really struggling to work this one out, and any help is much appreciated.
My HTML
<div class="portlet-visible red-arrow"></div>
My CSS
div.portlet-visible
{
position:absolute;
top:12px;
right:10px;
background-image:url(../images/red-arrow-up.png);
width:14px;
height:14px;
}
And finally my javascript
$(document).ready(function() {
$(".portlet-hidden" && ".portlet-visible").each(function() {
if ($("this").hasClass(".red-arrow")) {
$(this).css(background-image, url('"url(../images/blue-arrow-up.png)"')
};
});
});
Multiple selectors should be separated by a comma(,) and also css method takes a string or a map. Try this.
$(document).ready(function() {
$(".portlet-hidden, .portlet-visible").each(function() {
if ($(this).hasClass("red-arrow")) {
$(this).css('background-image', "url('../images/blue-arrow-up.png')")
};
});
});
I would have written the selector this way
$(".portlet-hidden, .portlet-visible")
Unless there's a specific reason you want to do this with jQuery you should just use CSS...
div.portlet-visible
{
background-image:url(../images/red-arrow-up.png);
width:14px;
height:14px;
}
div.portlet-visible.red-arrow
{
background-image:url(../images/blue-arrow-up.png);
}
Any div with the class "portlet-visible" is defined in the first block, and any div with the classes "portlet-visible" and "red-arrow" will use the same css, but also apply the new background image.
http://jsfiddle.net/johncmolyneux/gcm5b/
First... Archer's answer is spot on-- what you're trying to do with jQuery can be done with CSS alone.
But if for some reason you do need jQuery, a few things are wrong here.
First, as justtkt said in his answer, your selector is wrong. There is no need (and is syntactically wrong) to use conditional operators like && or || in a jQuery selector. This is simply because there is already conditional syntax built in to CSS, upon which jQuery selectors are directly based.
.this-class.that-class
Selects all elements with both .this-class, and .that-class.
#this-id.that-class
Is a very (possibly overly) specific declaration that select an element (there should only be one ID per page) with both #this-id and .that-class
For more on selectors, please read this very thorough, complete, and educational link http://www.w3.org/TR/selectors/
Additionally and importantly
This line:
$("this").hasClass(".red-arrow")
Is wrong! hasClass does not require a selector (the ".") because it only takes a class. It should be
$("this").hasClass("red-arrow")
Also!!
$(this).css(background-image, url('"url(../images/blue-arrow-up.png)"')
This line has some errors... should be:
$(this).css("background-image", "url(../images/blue-arrow-up.png)")
although I think the following syntax is easier:
css({'background-image' : 'url(../images/blue-arrow-up.png)'})
Your selector is just incorrect. If you want to match things with both classes, it'd be:
$('.portlet-hidden.portlet-visible').each( ...
If you want to match either of the classes:
$('.portlet-hidden, .portlet-visible').each( ...
The expression ".portlet-hidden" && ".portlet-visible" will always evaluate to just ".portlet-visible".
Instead of && two selectors together, use the multiple selector like $(".portlet-hidden, .portlet-visible") or the .add() method to build up your jQuery.
Your current line is actually anding the two strings together, which I believe will return boolean true in Javascript.
if ('$("this").hasClass(".red-arrow")') { <--- this condition is a string here
Should be:
if ($(this).hasClass(".red-arrow")) {
change in selector ".portlet-hidden,.portlet-visible"
change if condition to boolean from string
change in css.
$(".portlet-hidden,.portlet-visible").each(function(){
if ($("this").hasClass("red-arrow")){
$(this).css("background-image", "url('../images/blue-arrow-up.png')");
}
});

Select all elements that have a specific CSS, using jQuery

How can I select all elements that have a specific CSS property applied, using jQuery? For example:
.Title
{
color:red;
rounded:true;
}
.Caption
{
color:black;
rounded:true;
}
How to select by property named "rounded"?
CSS class name is very flexible.
$(".Title").corner();
$(".Caption").corner();
How to replace this two operation to one operation. Maybe something like this:
$(".*->rounded").corner();
Is there any better way to do this?
This is a two year old thread, but it was still useful to me so it could be useful to others, perhaps. Here's what I ended up doing:
var x = $('.myselector').filter(function () {
return this.style.some_prop == 'whatever'
});
not as succinct as I would like, but I have never needed something like this except now, and it's not very efficient for general use anyway, as I see it.
Thank you, Bijou. I used your solution, but used the jQuery .css instead of pure javascript, like this:
var x = $('*').filter(function() {
return $(this).css('font-family').toLowerCase().indexOf('futura') > -1
})
This example would select all elements where the font-family attribute value contains "Futura".
You cannot (using a CSS selector) select elements based on the CSS properties that have been applied to them.
If you want to do this manually, you could select every element in the document, loop over them, and check the computed value of the property you are interested in (this would probably only work with real CSS properties though, not made up ones such as rounded). It would also would be slow.
Update in response to edits — group selectors:
$(".Title, .Caption").corner();
Similar as Bijou's. Just a little bit enhancement:
$('[class]').filter(function() {
return $(this).css('your css property') == 'the expected value';
}
).corner();
I think using $('[class]') is better:
no need to hard code the selector(s)
won't check all HTML elements one by one.
Here is an example.
Here is a clean, easy to understand solution:
// find elements with jQuery with a specific CSS, then execute an action
$('.dom-class').each(function(index, el) {
if ($(this).css('property') == 'value') {
$(this).doThingsHere();
}
});
This solution is different because it does not use corner, filter or return. It is intentionally made for a wider audience of users.
Things to replace:
Replace ".dom-class" with your selector.
Replace CSS property and value with what you are looking for.
Replace "doThingsHere()" with what you want to execute on that
found element.
Good luck!
Custom CSS properties aren't inherited, so must be applied directly to each element (even if you use js to dynamically add properties, you should do it by adding a class), so...
CSS
.Title
{
color:red;
}
.Caption
{
color:black;
}
HTML
You don't need to define a rounded:true property at all. Just use the presence of the 'Rounded' class:
<div class='Title Rounded'><h1>Title</h1></div>
<div class='Caption Rounded'>Caption</div>
JS
jQuery( '.Rounded' ).corner();

this, current context-when should I use in jQuery?

I am not very sure with the use of "this" [current context] in jquery.What I know is- it prevents the dom from searching all the elements, it just work on that current element, which improve performance[correct me if I am wrong].Also I am not sure when to use this and when not.
lets say, should I go for
$("span",this).slice(5).css("display", "none")
or
$("span").slice(5).css("display", "none")
both will work, but I am not very clear as how really it works.can somebody explain it with a diff/proper example, and when to use what?
[EDIT]
$(function() {
$("#clickme").click(function() {
$("span",this).slice(5).css('display', 'block');//doesn't work ? why?
$("span").slice(5).css('display', 'block');//works..why?
});
});
enter code here <span id="clickme">Click me</span>
<span>itam1</sapn>
<span>itam2</sapn>
<span>itam3</sapn>
<span>itam4</sapn>
<span>itam5</sapn>
...upto10
Usually you can use the this keyword on event handlers since it will be a reference to the element that triggered the event and other jQuery functions like $.each.
For example when handling a click event lets say:
$('.parentElement').click(function () {
$('.foo', this).hide();
});
The above code, will hide all the elements with class foo that are descendants of the currently parentElement that was clicked.
The use of the context argument of the jQuery function is the equivalent of making a call to the find method:
$(expr, context);
// is just equivalent to:
$(content).find(expr);
EDIT: Looking at your example:
$("#clickme").click(function() {
$("span",this);//... (1)
$("span");//.. (2)
});
The first line, will look for all the span elements that are inside of #clickme (its descendants), since that element was the one that triggered the click event.
The second line, will look for all the span elements on the whole page.
How it works
Lets use this HTML for the examples:
<div id="container">
<div class="column">Link 1</div>
<div class="column">Link 2</div>
</div>
<div id="footer">
Link 3Link 3
</div>
The scoping parameter of the jQuery function should only be used if you already have a cached reference to a DOM element or jQuery wrapped element set:
var $set = $('#container');
$('a', $set).hide(); // Hides all 'a' tag descendants of #container
Or in an event:
$("#container").click(function(e){
$('a', this).hide(); // Same as call above
}
But it makes no sense to use it like this:
$('a', '#container').hide()
When it should be written like this:
$('#container a').hide();
Having said all that, it is generally cleaner and clearer to just use .find() instead of using the second parameter in the jQuery function if you already have the jQuery or DOM element. The first example I gave would be written this way instead:
var $set = $('#container');
$set.find('a').hide(); // Hides all 'a' tag descendants of #container
If this one call was the only reason you grabbed the #container object, you could also write it this way since it will still scope the search to the #container element:
$("#container a").hide(); // This is the same as $('a', "#container");
Why would you scope your selections
When jQuery looks for an unscoped selector, it will search through the entire document. Depending on the complexity of the selector, this could require a lot of searching. If you know that the element you are looking for only occurs within a specific parent, it will really speed up your code to scope the selection to that parent.
Regardless of what method of scoping you choose, you should always scope your selectors whenever possible.

Categories

Resources