Cleanest way to query for parent class using JQuery - javascript

I'm having trouble coming up with a solution that pleases me.
I'm working with some composite components, and I don't have full control over them, and now I have to set values to them using JavaScript, and I thought JQuery would serve me well, as it did.
What happens is that the component's HTML output has a structure simlar to this:
<span id="externalSpan">
<span id="internalSpan">
<input type="text" class="component-value" />
</span>
</span>
So all I had to do was check the component-value input, and if it's empty, I set the default value to it.
I solved it like this:
$(document).ready(function(){
var defaultValue = $('#defaultValue').val();
$('.component-value').each(function(){
if(!$(this).val()){
$(this).val(defaultValue);
}
});
});
And that worked fine, but now there's a new condition I need to evaluate. If the component has the manualInput CSS class, I cannot set it's value, but the class is set on the externalSpan which is the input's grandfather component, and it looks like this:
<span id="externalSpan" class="manualInput">
<span id="internalSpan">
<input type="text" class="component-value" />
</span>
</span>
The simplest way that I found to do it was this:
if(!$(this).parent().parent().hasClass('manualInput')){ ... }
And it works, but it seems really smelly to me, another solution was to invoke parents() with a class selector and check the length, but it seems odd too.
Is there a cleaner way for me to do this? And if not, which of the 2 options described above is a better solution?

So add the check to the selector
$('span:not(.manualInput) > span > .component-value').each(function(){
Example JSFiddle

I would use closest :
if(!$(this).closest('#externalSpan').hasClass('manualInput')){ ... }
Source : http://api.jquery.com/closest/

You can do this --
if($(this).closest('.manualInput').length > 0){
// do your stuff
}

A much better solution, use a selector that avoids .component-value elements that are descendants of .manualInput:
$('.component-value:not(.manualInput .component-value)').each(...)
Ideally the grandparent element would have a consistent class such that you could call .closest():
if ($(this).closest('.component-value-grandfather').hasClass('manualInput')) {...}
Alternatively you could check to see if there is a .manualInput ancestor at all:
if ($(this).closest('.manualInput').length) {...}

I'd recommend the following
$('span:not(.manualInput) > span').find('.component-value:empty').each(function () {
$(this).val(defaultValue);
});
Or better yet,
$('.component-value:empty', 'span:not(.manualInput) > span').val(defaultValue);
Probably, the shorted piece of code to achieve what you desire.

Alternatively you could use
if ($(this).parents('.manualInput').length) {/*...*/}
See jquery documentation. I suppose this is the shortest way to find the parent(s) of a given element

Related

Check is style attribute does not exists using javascript selector method

I'm trying to only select ARTICLE items that do not have the style attribute set.
I could do this easily with jQuery but I'm using a library that is javascript only, called scrollreveal.
I can easy get items that have the style attribute using this ARTICLE[style].
But I want to reverse this and get items that do not have a style attribute, in the same way using a not equal to != operator on the selector.
I've tried this...
// scroll reveal article
window.sr = new ScrollReveal({ reset: false });
sr.reveal('ARTICLE[!=style]', {
duration: 1000
});
But it's not working as expected, does anyone know if its possible to achieve this using not equal too on a attribute selector?
Thanks in advance for any help on this.
Almost there. The :not pseudoclass should do the trick:
article:not([style])
Just use :not([style]):
const matches = document.querySelectorAll('div:not([style])')
console.log(matches)
<div id="foo" style="width:100px;"></div>
<div id="bar"></div>
<div id="baz"></div>
That is if I'm correct in assuming that sr.reveal uses document.querySelector internally.

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 clone input with jQuery

I try to clone input field, but all I can do is to grab the value.
Here is the jsFiddle
When I try to do $('#input').html() i got and empty string.
I know that the answer is somewhere on the surface, but I can't find it. Please help.
EDIT
I DO NOT NEED a value. I said - i can do it. I need to CLONE the input as HTML. What here is not understandable?
EDIT 2
I tried to clone an element and get html with this:
$('#text').clone().html()
but it returns an empty value too. Although if I try to get a val:
$('#text').clone().val()
It returns a value normally
I think that's what you're trying to do :
<input id='test' value='10201' />
<p id="input-text"> Hello </p>
Then in jQuery :
var inputField = $('#test').clone();
$('#input-text').html(inputField);
As answered on this answer... You can use Javascript to get the outerHTML.
var inputHTML = $('#input')[0].outerHTML;
Then you can use that variable wherever you need to on the page!
Hope that helps!
EDIT: You can do this purely using jQuery, again, an answer on the above linked question...
$.fn.outerHTML = function() {
return $(this).clone().wrap('<div></div>').parent().html();
};
var inputHTML = $("#input").outerHTML());
What about
$('#input-text').html($('#test').clone().removeAttr('value'));
The method your are looking for is clone()
Using the .clone() method to the specific DOM element will extract the HTML(everything about it gets duplicated, raw) inherently.
$("#test").clone().appendTo("#input-text").removeAttr('value');
$("input:eq(1)").attr("id", "test_02");
input {
margin-left: 3px;
border: solid 1px #ACE;
width: 3.05em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<input id='test' value='10201' />
<p id="input-text">Hello</p>
The .attr() method was added only to raise awareness of the one pitfall of utilizing the .clone() method - that being, it duplicates the id of the DOM element which is not best practice or even allowed in standard HTML programming. The best pratice in this case, would probably be to create a unique class that you know, will only deal with that specific DOM element so it can be duplicated as you like.
Additional Resources
» Fiddle Example
» clone() API
» appendTo() API
» Class VS ID

select html object without id

Edit: one missing piece of information - I can't use the class selector because there are more divs with the same class. I already thought of that, but I forgot to mention it. I have no idea why my post got downvoted, but it seems awfully silly considering I provided a lot of information, gave it honest effort, and tried to be verbose with code examples. People on this forum are ridiculous sometimes.
I'm trying to set the id of a div that doesn't have one and there's no way I can give it one upon generation of the page. I've tried using jquery (.each, .contains, .find, .filter, etc.) and I can't seem to get it right. I know a ton of people have asked this question, but none of the answers made sense to me.
I have the ability to set the text (html?) of the div, but nothing else. It ends up looking like this:
<div class="dhxform_note" style="width: 300px;">Remaining letters: 500</div>
I want a handle to the div object so I can show the user how many more letters they can type by updating the text.
Using this:
$("div")
returns a list of all divs on the page. I can see the target div in the list, but I can't get jquery to return a single object.
I know it can also be done with something like this:
var divs = document.getElementsByTagName("div");
for(var i = 0; i < divs.length; i++) {
if( /^Remaining letters/.test(divs[i].innerText) )
divs[i].id = "kudosMsgNote"
}
}
but I was hoping to complete this with a cleaner looking solution involving jquery. I also simply want to know how to do it with jquery, aesthetics not withstanding.
Use a class selector.
var theDivViaTheClass = $(".dhxform_note");
Class Selector (“.class”)
Description: Selects all elements with the given class.
version added: 1.0
jQuery( ".class" )
class: A class to search for. An
element can have multiple classes; only one of them must match.
For class selectors, jQuery uses JavaScript's native
getElementsByClassName() function if the browser supports it.
You seem to be targeting the <div> by its text. Try using the :contains selector:
$("div").filter(':contains("Remaining letters")').first().attr("id", "kudosMsgNote");
The .first() is to make sure you don't set the same id for multiple elements, in case multiple elements contain the text "Remaining letters".
Here's the docs for the :contains selector: http://api.jquery.com/contains-selector/
Be careful, the text you're looking for is case sensitive when using :contains!
Is that div the only one with the class dhxform_note? If so, you can use the class selector:
$('.dhxform_note').html();
With jQuery, you can specify any css selector to get at the div:
$(".dhxform_note").attr("id", "kudosMsgNote");
will get you this element as well.
Selecting on inner text can be a bit dicey, so I might recommend that if you have control over the rendering of that HTML element, you instead render it like this:
<div name="remainingLetters" class="dhxform_note" style="width: 300px">Remaining Letters: 500</div>
And get it like this:
$("[name=remainingLetters]").attr("id", "kudosMsgNote");
However, it's possible that you really need to select this based on the inner text. In that case, you'll need to do the following:
$("div").each(function() {
if ( /^Remaining letters/.test($(this).html()) ) {
$(this).attr("id", "kudosMsgNote");
}
});
If you cannot set id for whatever reason, I will assume you cannot set class either. Maybe you also don't have the exclusive list of classes there could be. If all those assumptions really apply, then you can consider down your path, otherwise please use class selector.
With that said:
$("div").filter(function() {
return /^Remaining letters/.test($(this).text())
}).attr('id', 'id of your choice');
For situations where there are multiple divs with the class dhxform_note and where you do not know the exact location of said div:
$("div.dhxform_note").each(function(){
var text = $(this).text();
if(/^Remaining letters/.test(text)){
$(this).attr("id", "kudosMsgNote");
}
});
EXAMPLE
If, however, you know that the div will always be the 2nd occurrence of dhxform_note then you can do the following:
$("div.dhxform_note").get(1).id = "kudosMsgNote";
EXAMPLE
Or do a contains search:
$("div.dhxform_note:contains('Remaining letters')").first().attr("id", "kudosMsgNote");
EXAMPLE

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')");
}
});

Categories

Resources