jQuery selector by classname minus classname - javascript

I have the following jquery line in a click event of a p element:
$(this).nextUntil('.Maintheme not:.Document')
I would like to get all the next elements with class .Maintheme but not .Document.
To explain myself a little better, this is the html that i have:
<div id="DocumentContents">
<p class="Maintheme">ParentTheme1</p>
<p class="Document">Document1</p>
<p class="Maintheme">ParentTheme2</p>
<p class="Subtheme">SubTheme1</p>
<p class="Document">Document1</p>
<p class="Document">Document2</p>
<p class="Document">Document3</p>
<p class="Subtheme">SubTheme2</p>
<p class="Document">Document1</p>
</div>
Having this html content i would like that when you click in a p element if there is not subthemes then show documents. Else if there are subthemes with documents below, just show the subthemes, and if you click in a subtheme show the next documents.

Something like this?
Example: http://jsfiddle.net/ZSCs3/
$('p:not(.Maintheme)').hide();
$('.Maintheme').click(function() {
var $this = $(this)
if ($this.next('.Subtheme').length) {
$this.nextUntil('.Maintheme').filter('.Subtheme').toggle();
} else {
$this.nextUntil('.Subtheme,.Maintheme').toggle();
}
});
$('.Subtheme').click(function() {
$(this).nextUntil('.Subtheme,.Maintheme').toggle();
});

You should use .nextAll().
var $themes = $(this).nextAll('.Maintheme');
You have to do some if-statements from there to create the logic you want.
if($themes.length){
}
else{
}
Anyways, this looks odd to me. You should use a nested list for instance to display such kind of structures.
Ref.: .nextAll()

You don't have the not syntax quite correct but it's not clear to me exactly what you are asking for so I won't try and correct it for you, just point you at the reference. I agree that this looks a bit off anyway.

I think that the not() jQuery selector is more suitable for your case since the nextUntil() selector will stop gathering the elements with the Maintheme class on the first occurence of p tag styled with Document class. Hence you can use code slice like this:
$(this).not(':.Maintheme').css(hidePtagsWithDocumentclass);

Related

jQuery refactoring, how to avoid repetitive code?

I know this is awfully simple, but I'm new to this and I just need to be shown it once. So when I'm using jQuery/javascript I find myself writing repetitive code again and again to target different elements with the same function, for example:
$(function() {
$('.icon1').click(function() {
$('.info1').toggle().addClass('animated fadeInDown');
$('.info2, .info3, .info4').hide();
});
});
$(function() {
$('.icon2').click(function() {
$('.info2').toggle().addClass('animated fadeInLeft');
$('.info1, .info3, .info4').hide();
});
});
and this repeats again for icon3 and icon4. I'm selecting a different element, showing another, hiding another three, and adding different classes in each function, and I don't know what would be the best way not to repeat the whole thing for each element. I would be very glad to be shown any ideas to refactor this, and wouldn't mind seeing how that is done in vanilla js also.
(For illustration the code here is a snippet from the code on the experience section of my portfolio where clicking on an icon reveals an info panel about it, and hides any previously shown info panels.)
Use a common class, use this, and not to remove it from the collection
$(function() {
$('.commonClass').click(function() {
$(this).toggle().addClass('animated fadeInDown');
$('.commonClass').not(this).hide();
});
});
You should be able to separate those selectors with commas.
$('.icon1,.icon2').click(function()
Or assign each a single class they share that behavior? ".icon-btn" where you use ".icon-btn" as the selector for any you wish to have that behavior.
It would be better if you can plan your html better with data attribute
for eg:
<div class="icon" data-info = "1"> <div>
<div class="icon" data-info = "2"> <div>
<div class="info-1 info"> <div>
<div class="info-2 info"> <div>
$('.icon').click(function() {
var className = '.info-' + $(this).data('info');
$('.info').hide();
$(className).toggle().addClass('animated fadeInDown');
});
you can also remove .info1,.info2 from js code by adding some common class in html as info to them.
for eg
I'm making some assumptions about your actual HTML, but you could probably leverage the siblings() method in this case.
$(document).on('click', '.icon', function() {
$(this).toggle().addClass('animated fadeIn')
.siblings().hide();
});

How to simplify repeated and convoluted js/jquery code?

This piece of code appears in a js script I have been asked to modify - I'm not sure why it is written in this way, it doesn't make sense to me.
Can anyone help explain what it is doing, and if it can be simplified to be a little more meaningful?
var unformathtml = $(this).text();
if(unformathtml.trim().length>showChar) {
$(this).parent().parent().parent().parent().parent().find('.comment-footer').fadeOut();
}
Lets' pretend we have a DOM like this:
<parent-5>
<target-element>Content</target-element>
<parent-4>
<parent-3>
<parent-2>
<parent-1>
<focused-element>Some Text</focused-element>
</parent-1>
</parent-2>
</parent-3>
</parent-4>
</parent-5>
What this code is saying is "if the text inside of <focused-element> has more characters than showChar then fade out <target-element>.
A better way of doing this would be to give <parent-5> some kind of identifier, which could be an ID or a class, and target that instead of the repeated .parent() call.
Here's an example which showcases the idea:
$('#oldMethod').click(function() {
$(this)
.parent()
.parent()
.parent()
.parent()
.parent()
.find('.comment-footer')
.toggleClass('red');
});
$('#newMethod').click(function() {
$(this)
.closest('.comment-container')
.find('.comment-footer')
.toggleClass('red');
});
.red {
color: #F00;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="comment-container">
<div>
<div>
<div>
<div>
<button id="oldMethod">Old</button>
<button id="newMethod">New</button>
</div>
</div>
</div>
</div>
<div class="comment-footer">Footer</div>
</div>
Wow, that really doesn't make much sense. It is doing this:
1) Getting the raw contents out of an element
2) Checking to see if it is longer than a certain length
3) If so, fading out another element on the page
The parents() thing is very error-prone. It is going up a very precise number of levels in the HTML tree and then descending downwards to find an element with a class of '.comment-footer'. As a result a slight rearrangement of either element in the DOM might result in the code no longer working, because it can't find the specified element.
What you want is to find the tag-to-hide more directly. Ideally, the element-to-hide and the element-that-decides-to-hide would be next to eachother in the DOM (i.e. the element being hidden would be a child or sibling of the element that decides whether or not to hide it). This makes it very easy for the one to find the other. If that isn't possible, your next best bet would be to simply assign an id to the element you are trying to hide and then select on that id directly:
var unformathtml = $(this).text();
if(unformathtml.trim().length>showChar) {
$('#to_hide').fadeOut();
}
As a quick aside, .text() is used (instead of .html()), because the former removes any HTML tags. This way you are measuring the amount of "actual" text inside $(this) to determine whether or not you want to hide said element. So that part is probably fine.

Move element before second to last h2 with jQuery

I am trying to move an elmement with class .books_inarticle_list from its native possition tu just before the second to last H2.
I am using the following which is not working:
$('.books_inarticle_list').insertBefore('#content_column > h2:nth-last-child(2)');
On the other hand something like this works:
$('.books_inarticle_list').insertBefore('#content_column > h2:nth-of-type(6)');
So the issue must be with the nth-last-child() selector, but I don't see what it might be.
Does anyone see anything wrong with that code or knows an alternative way to move that element to just before the second to last H2 tag?
Try the .get() method, which supports negative numbers to go in reverse.
$('.books_inarticle_list').insertBefore($('#content_column > h2').get(-2));
Edit On second thought, it makes more sense to follow your own examples and use the :nth-last-of-type() selector, which will go in reverse.
$('.books_inarticle_list').insertBefore('#content_column > h2:nth-last-of-type(2)');
The reason :nth-last-child() isn't working for you is because that, and :nth-child(), refers to the number of siblings they have in the DOM, not the list of elements returned by the selector.
You'd be better off providing your HTML for the optimal solution, however given your question I'd suggest something like the following:
var $h2s = $("#content_column > h2");
var $secondToLast = $h2s.eq($h2s.length-2);
$('.books_inarticle_list').insertBefore($secondToLast);
I passed on using nth-child just because that will be thrown off any time you modify your HTML structure.
Note, :nth-* selectors use 1-based indexing. You can use :nth-last-of-type() selector with 2 as parameter to selector second from last element of that type, chain .before() with $(".books_article_list") as parameter.
$("#content_column h2:nth-last-of-type(2)").before($(".books_article_list"));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="books_article_list">books</div>
<div id="content_column">
<h2>0</h2>
<h2>1</h2>
<h2>2</h2>
<h2>3</h2>
<h2>4</h2>
<h2>5</h2>
<h2>6</h2>
</div>
i prefer to use ":eq" even ":nth-of-type". So will be :
$('.books_inarticle_list').insertBefore('#content_column > h2:eq('+($('#content_column > h2').length()-2)+')');

How to remove a href that is listed under div tag?

I'm modifying a part of my wordpress theme and I have come across an issue. I want to remove the ability to click on a link though I do not have the ability to modify the class names or set ID tags
HTML:
<div class="one">
foobar.com
</div>
I have tried to remove the functionality by writing this JavaScript:
document.getElementsByClassName("one")
.getElementsByTagName("a")
.removeAttribute("href");
However this method does not work, am I doing something wrong?
You can use css.
.one a {
pointer-events: none;
}
and you can also remove the hand cursor by adding cursor: default;
document.getElementsByTagName("a")[0].removeAttribute("href");
<div class="one">
foobar.com
</div>
No need to target .one first. Just target by getElementsByTagName but remember that this returns an array of elements, so you need to reference the index of the element you want to remove.
document.getElementsByTagName("a")[0].removeAttribute("href");
If you need to select only the links in the "one" class, you'll need to index into what you get back from getElementsByClass then call children and index into that:
document.getElementsByClassName("one")[0].children[0].removeAttribute("href")
You can do it this way:
document.getElementById("text").onclick = function(){
var clickStatus = true; // Change this to true if you want to enable the link.
if (clickStatus){
window.location = "http://foobar.com";
}
}
<div class="one">
<section id="text">foobar.com</section>
</div>
It will generate Type Error because getElementsByClassName function will return a node list not a single node so you will need to do the following:
document.getElementsByClassName("one")[0]
.getElementsByTagName("a")[0]
.removeAttribute("href");
or
document.querySelector(".one a").removeAttribute("href");
Any method of the above will solve your problem
I hope it helps
I think you need to disable the Href functionalities here.
Please use Jquery :
$('.one > a').on('click',function(e){
e.preventDefault();
}
Hope this will work for you

How to keep only one element if there are more than one

Every time I load a page, I have a random number of elements with the same class and different(random) IDs.
I would like to know how I can keep only one element on the page and delete the others from DOM, according to their class?
Example:
<div id="joke" class="hey"></div>
<div id="joking" class="hey"></div>
<div id="jokes" class="hey"></div>
<div id="joker" class="hey"></div>
I would like to leave only id="joke" where joke (as for the other element's id values) is randomly/dynamically generated.
If you only want to keep the first one:
$('.hey').slice(1).remove();
Reference: .slice(), .remove()
If you want the first one, you can use:
$(".hey").first();
If you want a random element from those matched, you can use the :random filter implemented here and do:
$(".hey:random");
I noticed that there are only answers here that assume jQuery is available. While obviously jQuery is without a doubt perfect and should be elected president I'm going to assume that it's NOT available. Let's do this (removing all except the first element) just using the DOM shall we. (see JSfiddle)
<div id="foo">
<!-- a jocular comment -->
<div id="joke" class="hey">1</div>
<div id="joking" class="hey">2</div>
<div id="jokes" class="hey">3</div>
<div id="joker" class="hey">4</div>
</div>
js:
var parent = document.getElementById('foo'),
elems = parent.childNodes, // live list
firstElemNode,
i = 0;
while (elems[i] && elems[i].nodeType != 1) {
i++;
}
if (elems[i]) {
firstElemNode = parent.removeChild(elems[i]);
parent.innerHTML = '';
parent.appendChild(firstElemNode);
}
We look for the first node that is an element (not a text node or comment node). If we can't find one we are smart enough to do nothing.
var $els = $('.hey');
$els.not($els.eq(Math.floor(Math.random()*$els.length))).remove();
JSFiddle
Try this
$('.hey').not('#joke').remove()
$('div.hey:not(:first)').remove()
To show a random .hey element:
$('.hey').hide();
$('.hey')[Math.floor(Math.random()*$('.hey').length)].show();

Categories

Resources