How to run a for loop inside a jQuery selector? - javascript

I am programming a WebExtension for Facebook which will invoke CSS based on their privacy settings.
$(document).ready(function(){
$("a[data-tooltip-content*='Public']").closest(".userContentWrapper._5pcr").css({"background-color": "yellow"});
$("a[data-tooltip-content*='Only Me']").closest(".userContentWrapper._5pcr").css({"background-color": "lime"});
$("a[data-tooltip-content*='friends']").closest(".userContentWrapper._5pcr").css({"background-color": "cyan"});
$("a[data-tooltip-content*='Public']").closest("._2tdc").css({"background-color": "yellow"});
$("a[data-tooltip-content*='Only Me']").closest("._2tdc").css({"background-color": "lime"});
$("a[data-tooltip-content*='friends']").closest("._2tdc").css({"background-color": "cyan"});
However, I noticed that a different page layout are has a different class value that I need to invoke with CSS codes.
Is there any way to write a for loop inside a jQuery selector?
$("a[data-tooltip-content*='Public']").closest("**For(a list of class name), loop through all of them)**").css({"background-color": "yellow"});
I have tried using $.each jQuery, but I really don't have much of an idea after reading through the documents.
var obj = {".userContentWrapper._5pcr" , "._2dc"};
$.each(obj, function(index,element)){
$("a[data-tooltip-content]").closest(obj).css({"background-color": "violet"});
$("a[data-tooltip-content*='Public']").closest(obj).css({"background-color": "yellow"});
$("a[data-tooltip-content*='Only Me']").closest(obj).css({"background-color": "lime"});
$("a[data-tooltip-content*='friends']").closest(obj).css({"background-color": "cyan"});
}
Sample result (original image link):

This should be as easy as storing all the class names in an array, and using a loop
var classses = ['.class1','.class2'];
for(var i=0;i<classes.length;i++)
$("a[data-tooltip-content*='Public']").closest(classes[i]).css({"background-color": "yellow"});
However, in general, multiple selectors can be separated with commas so this may also work.
$("a[data-tooltip-content*='Public']").closest('.class1, .class2')
.css({"background-color": "yellow"});

You almost did it yourself
$("a[data-tooltip-content*='Public']").closest(".class1, .class2, .class3").css({"background-color": "yellow"});

Related

show all the values with .html [duplicate]

Lets say I have an empty div:
<div id='myDiv'></div>
Is this:
$('#myDiv').html("<div id='mySecondDiv'></div>");
The same as:
var mySecondDiv=$("<div id='mySecondDiv'></div>");
$('#myDiv').append(mySecondDiv);
Whenever you pass a string of HTML to any of jQuery's methods, this is what happens:
A temporary element is created, let's call it x. x's innerHTML is set to the string of HTML that you've passed. Then jQuery will transfer each of the produced nodes (that is, x's childNodes) over to a newly created document fragment, which it will then cache for next time. It will then return the fragment's childNodes as a fresh DOM collection.
Note that it's actually a lot more complicated than that, as jQuery does a bunch of cross-browser checks and various other optimisations. E.g. if you pass just <div></div> to jQuery(), jQuery will take a shortcut and simply do document.createElement('div').
EDIT: To see the sheer quantity of checks that jQuery performs, have a look here, here and here.
innerHTML is generally the faster approach, although don't let that govern what you do all the time. jQuery's approach isn't quite as simple as element.innerHTML = ... -- as I mentioned, there are a bunch of checks and optimisations occurring.
The correct technique depends heavily on the situation. If you want to create a large number of identical elements, then the last thing you want to do is create a massive loop, creating a new jQuery object on every iteration. E.g. the quickest way to create 100 divs with jQuery:
jQuery(Array(101).join('<div></div>'));
There are also issues of readability and maintenance to take into account.
This:
$('<div id="' + someID + '" class="foobar">' + content + '</div>');
... is a lot harder to maintain than this:
$('<div/>', {
id: someID,
className: 'foobar',
html: content
});
They are not the same. The first one replaces the HTML without creating another jQuery object first. The second creates an additional jQuery wrapper for the second div, then appends it to the first.
One jQuery Wrapper (per example):
$("#myDiv").html('<div id="mySecondDiv"></div>');
$("#myDiv").append('<div id="mySecondDiv"></div>');
Two jQuery Wrappers (per example):
var mySecondDiv=$('<div id="mySecondDiv"></div>');
$('#myDiv').html(mySecondDiv);
var mySecondDiv=$('<div id="mySecondDiv"></div>');
$('#myDiv').append(mySecondDiv);
You have a few different use cases going on. If you want to replace the content, .html is a great call since its the equivalent of innerHTML = "...". However, if you just want to append content, the extra $() wrapper set is unneeded.
Only use two wrappers if you need to manipulate the added div later on. Even in that case, you still might only need to use one:
var mySecondDiv = $("<div id='mySecondDiv'></div>").appendTo("#myDiv");
// other code here
mySecondDiv.hide();
if by .add you mean .append, then the result is the same if #myDiv is empty.
is the performance the same? dont know.
.html(x) ends up doing the same thing as .empty().append(x)
Well, .html() uses .innerHTML which is faster than DOM creation.
.html() will replace everything.
.append() will just append at the end.
You can get the second method to achieve the same effect by:
var mySecondDiv = $('<div></div>');
$(mySecondDiv).find('div').attr('id', 'mySecondDiv');
$('#myDiv').append(mySecondDiv);
Luca mentioned that html() just inserts hte HTML which results in faster performance.
In some occassions though, you would opt for the second option, consider:
// Clumsy string concat, error prone
$('#myDiv').html("<div style='width:'" + myWidth + "'px'>Lorem ipsum</div>");
// Isn't this a lot cleaner? (though longer)
var newDiv = $('<div></div>');
$(newDiv).find('div').css('width', myWidth);
$('#myDiv').append(newDiv);
Other than the given answers, in the case that you have something like this:
<div id="test">
<input type="file" name="file0" onchange="changed()">
</div>
<script type="text/javascript">
var isAllowed = true;
function changed()
{
if (isAllowed)
{
var tmpHTML = $('#test').html();
tmpHTML += "<input type=\"file\" name=\"file1\" onchange=\"changed()\">";
$('#test').html(tmpHTML);
isAllowed = false;
}
}
</script>
meaning that you want to automatically add one more file upload if any files were uploaded, the mentioned code will not work, because after the file is uploaded, the first file-upload element will be recreated and therefore the uploaded file will be wiped from it. You should use .append() instead:
function changed()
{
if (isAllowed)
{
var tmpHTML = "<input type=\"file\" name=\"file1\" onchange=\"changed()\">";
$('#test').append(tmpHTML);
isAllowed = false;
}
}
This has happened to me . Jquery version : 3.3.
If you are looping through a list of objects, and want to add each object as a child of some parent dom element, then .html and .append will behave very different. .html will end up adding only the last object to the parent element, whereas .append will add all the list objects as children of the parent element.

jQuery how to do the following

I've the following question, let say we have a div like this:
These are dynamically formatted divs, with the classes 'row', 'element' and 'isotope-item' are always present. Everything in between can vary per div.
What I want is to the following:
As you see the commmas are no longer there and seperate classes between the commas are now one class.
Anyone any idea?
I already have the following to remove the commas:
$('div.element').each(function () {
var _sCurrClasses = jQuery(this).attr('class');
jQuery(this).attr('class', _sCurrClasses.replace(/,/g, ' '));
});
I would advise doing this backend,but in JavaScript you could:
This will not account for the space in the words though.
You would need to pass then trough separately one by one and replace.
or store them in a data-attribute and format when you need them.
<string>
var classesFormat = classes.replace(/,/g, '');
var classesList = classesFormat.split(" ");
for(String c : classesList)
{
$("#id").addClass(c);
}
</string>
So you could create a data-attribute for each one instead.
Go through each one, format and the add to class.
<div data-id="Microsoft Office," class="test test test">
With the script
$(this).attr("data-id") // will return the string "Microsoft Office,"
or .data() (if you use newer jQuery >= 1.4.3)
$(this).data("id") // will return the Microsoft Office,
And then do your replace after that and addClass.
I don't think classes work like you think they do
the first PICTURE you posted would result in that div having the follwing classes
row
element
Microsoft
Office,
My
SQL,
Page
Rank
isotope-item
Note the , is PART of the class
You want, according to the second PICTURE
row
element
MicrosoftOffice
MySQL
Page
Rank
isotope-item
Removing , is just as you posted ... the problem is, how do you determine which spaces to remove, and which to keep?
(I posted this as an ANSWER, but I KNOW IT IS NOT AN ANSWER)

Problem with JS, DOM and looping

I have a problem with JavaScript looping and DOM.
so I have a few div's, each has a background image defined by CSS, however when i rollover a text link, i wish for these background images to change, which ones will change depends on their class name and the link mouseover'ed
<div id="im1" class="web"></div>
<div id="im2" class="logo"></div>
<div id="im3" class="web"></div>
<div id="im4" class="logo"></div>
<div id="5" class="logo"></div>
web
so those are the divs with my link for the mouse over.
then to change these images i have some simple JavaScript, which works fine (if very long)....
function showweb() {
document.getElementById("im1").style.backgroundImage = "url('back/1col.png')";
document.getElementById("im2").style.backgroundImage = "url('back/2col.png')";
however, i wondered if there was a way i would condition by class name, and only change those with a certain class name, eg web, or logo. ive tried various ways and loops and things, but none seemed to work.
e.g
function showweb() {
for(i=0; i=5; i++){
url = "im" + i;
if(document.getElementById("url").className=="web"){
document.getElementById("url").style.backgroundImage = "url('back/"+ i +"col.png')";}
}
}
however this doesn't work, the divs just don't change..... am i doing something wrong? missing something? or doing it the completely wrong way?
all help appreciated, thanks in advance.
Edit: changed the "url" to url, my bad, that was very foolish, however still didnt work. i will try a few other ideas posted.
thanks everyone so far.
You don't need the quotes around url:
document.getElementById(url)
This may work (if the link to your images is right and presumed that by id="5" you mean id="im5". Play with it until it's right. Check your code thourougly, there were several errors (typos or worse 1) in your coding:
function showweb() {
for(var i=1; i < 6; i++){
var el = document.getElementById("im"+(i));
if(el && /web/.test( (el ||{}).className)){
el.style.backgroundImage = "url(back/"+ i +"col.png)";}
}
}
1 a few notes on that
id = "5" should supposedly be id ="im5"
i=0; i=5; i++ => i=5 should be i<5
i=0; i=5; i++ creates a global variable i. Use var i=0;...
given your id's, you should start with var i = 1
though not a real error, you don't need to surround the url value with apostrophes
to optimize call document.getElementById once and use it's result in the rest of the code
You're building the "url" variable, but then you pass the string constant "url" into the "getElementById()" function.
To get only elements of the desired class, you need node.getElementsByClassName('your_class'), where node can be document or some <div> selected by id, or any other node of the DOM tree.
Note: Remember that all methods that start with getElement will return single element, and those with getElements will return an array of elements, so this one returns an array which you need to iterate (even if there is only one element in it)
However, since you are working with DOM elements in JavaScript, you would save tons of time by using jQuery
You have a few of problem. First, you have quotes around the variable "url" so it's looking for an element with that id, which doesn't exist and thus fails when you attempt to access the className of a null lookup result. Second, your loop starts at 0, not one and you don't have a div with id "im0" so it would fail anyway when you attempt to get the className of that element, which also doesn't exist. Third, the check in your loop sets i to 5 instead of checking if it is less than or equal to 5. Your loop with thus continue forever, since 5 equates to true, which I'm sure is not what you want. Fourth, your code may break if you assign additional classes to the elements. Lastly, most of this sort of thing has already been done for you -- might I suggest you look into using a javascript framework, such as jQuery -- with the hover() method, as a better alternative than re-inventing the wheel if this isn't purely a learning exercise.

Using javascript to insert id into list elements

I am messing around with a deck of cards that I made.I have it set up so that there is a method that spits out cards by suit into a list, so if I want spades I get a <ol> of all of the spades cards. I am now trying to give each <li> element an id depending on what card it is. ace will be <li id="ace"><img src="ace_spades.gif"/></li> king will be <li id="king"><img src="king_spades.gif"/></li> for example.The list is in order from top to bottom akqj1098765432 . I tried doing this:
var card_id=["ace","king","queen","jack","ten","nine","eight","seven","six","five","four", "three","two"];
var counter=0;
while (counter<=12)
{
$(document).ready(function(){
$("li").eq(counter).attr("id", card_id[counter])
});
counter++;
}
but it doesn't work. I have not really done anything with javascript before besides simple jquery stuff. What am I getting wrong here?
Try this:
$(document).ready(function(){
var card_id = ["ace","king","queen","jack","ten","nine","eight","seven","six","five","four", "three","two"];
$.each(card_id, function(i,id){
$("li").eq(i).attr('id',id);
});
});
You should try to only have one $(document).ready() function and it's not necessary to use a while() loop.
I think you don't need to call $(document).ready() function in the while. Try this:
var card_id=["ace","king","queen","jack","ten","nine","eight","seven","six","five","four", "three","two"];
var counter=0;
while (counter<=12){
$("li").eq(counter).attr("id", card_id[counter]);
counter++;
}
You do not need the document ready function. Place your script just before </body> and after the jquery.js script. This is working for me.
Check working example at http://jsfiddle.net/H8MeG/2/
First of ID's in a webpage have to be unique. Some browsers might ignore id's of elements that have already been used. Other browsers might fail completely...
Second off. you shouldn't use .eq() like that.
You definitely shouldn't add 12 new $(document).ready() statements.
Here's a more reliable version and the example on jsfiddle
var card_id=["ace","king","queen","jack","ten","nine","eight","seven","six","five","four", "three","two"];
$("#spades li").each(function(index){
$(this).attr("class", card_id[index]);
$(this).text(card_id[index]);
});
I also added $(this).text(card_id[index]); so you see it actually works. Try to uses classes for multiple elements that share the same characteristic.
why are you messing with ids at all?
you know that the first item is the ace, the second the king, and so on.
ol.getElementsByTagName('li')[12]='deuce'

What's the best way to get this data to persist within Javascript event handlers using jQuery

My code is meant to replace radio buttons with dynamic ones, and allow clicking both the label and new dynamic radio element to toggle the state of the hidden with CSS radio box.
I need to send to questions.checkAnswer() three parameters, and these are defined within these initiation loops. However I always get last the last values once the loop has finished iterating. In the past I've created dummy elements and other things that didn't feel right to store 'temporary' valuables to act as an informational hook for Javascript.
Here is what I have so far
init: function() {
// set up handlers
moduleIndex = $('input[name=module]').val();
$('#questions-form ul').each(function() {
questionIndex = $('fieldset').index($(this).parents('fieldset'));
$('li', this).each(function() {
answerIndex = $('li', $(this).parent()).index(this);
prettyRadio = $('<span class="pretty-radio">' + (answerIndex + 1) + '</span>');
radio = $('input[type=radio]', this);
radio.after(prettyRadio);
$(radio).bind('change', function() {
$('.pretty-radio', $(this).parent().parent()).removeClass('selected');
$(this).next('.pretty-radio').addClass('selected');
questions.checkAnswer(moduleIndex, questionIndex, answerIndex);
});
prettyRadio.bind('click', function() {
$('.pretty-radio', $(this).parent().parent()).removeClass('selected');
$(this).addClass('selected').prev('input').attr({checked: true});
});
$('label', this).bind('click', function() {
$(radio).trigger('change');
questions.checkAnswer(moduleIndex, questionIndex, answerIndex);
$(this).prev('input').attr({checked: true});
});
});
});
Is it bad to add a pretend attribute with Javascript, example, <li module="1" question="0" answer="6">
Should I store information in the rel attribute and concatenate it with an hyphen for example, and explode it when I need it?
How have you solved this problem?
I am open to any ideas to make my Javascript code better.
Thank you all for your time.
It's not the end of the world to add a custom attribute. In fact, in many cases, it's the least bad approach. However, if I had to do this, I would prefix the attribute the with "data-" just so that it is compliant with HTML5 specs for custom attributes for forward compatibility. This way, you won't have to worry about upgrading when you want to get HTML5 compliant.
you need to say 'var questionIndex' etc, else your 'variables' are properties of the window and have global scope...
regarding custom attributes, i have certainly done that in the past tho i try to avoid it if i can. some CMS and theming systems occasionally get unhappy if you do this with interactive elements like textareas and input tags and might just strip them out.
finally $(a,b) is the same as $(b).find(a) .. some people prefer the second form because it is more explicit in what you are doing.
If the assignment of the custom attributes is entirely client-side, you must resolve this with jQuery data, something like this:
$("#yourLiID").data({ module:1, question:0, answer:6 });
for the full documentation see here

Categories

Resources