I do a for loop in javascript to get the title and description for each item in my json file.
for (var i = 0, len = mydata.texts.length; i < len; i++) {
list +="<li>"+"<div class='circle'></div>" +
"<span onclick='toggleDesc()'>"+ mydata.texts[i]["keyword"] +
"</span>"+
+"</li>"+
"<div id='descr'>"+mydata.texts[i]["description"]+"</div>";
}
function toggleDesc() {
var x = document.getElementById('descr');
if (x.style.display === 'none') {
x.style.display = 'block';
} else {
x.style.display = 'none';
}
}
The result is like:
1. Title1
description1
2. title2
description2
3. Title3
Description3
...
Currently:
it is only toggling the first list item.
question
How can I fix it to show each list item's description on click?
Identifiers in HTML must be unique. However you can use CSS class with multiple time which can be targeted by using Class Selector .class.
for (var i = 0, len = mydata.texts.length; i < len; i++) {
list +="<li>"+"<div class='circle'></div>" +
"<span class='toggleDesc'>"+ mydata.texts[i]["keyword"] +
"</span>"+
"<div class='descr'>"+mydata.texts[i]["description"]+"</div>" +
"</li>";
}
Note: I have placed descr as sibling of SPAN as <ul>/<ol> can only have LI as child
Also I would recommend, unobtrusive event handlers instead of using ugly inline event handlers.
$(document).on('click', '.toggleDesc', function(){
$(this).next('.descr').toggle();
});
References .next() and use .on() method with Event Delegation approach for dynamically generated elements. And In place of document you should use closest static container for better performance.
You have multiple elements with id descr. ids should be unique. Consider doing something this:
for (var i = 0, len = mydata.texts.length; i < len; i++) {
list +="<li>"+"<div class='circle'></div>" +
"<span onclick='toggleDesc(" + i + ")'>"+ mydata.texts[i]["keyword"] +
"</span>"+
"<div id='descr" + i + "'>"+mydata.texts[i]["description"]+"</div>"
+"</li>";
;
}
function toggleDesc(i) {
var x = document.getElementById('descr' + i);
if (x.style.display === 'none') {
x.style.display = 'block';
} else {
x.style.display = 'none';
}
}
Currently:
it is only toggling the first list item.
Because you can't use the same id with multiple elements in a page as it must be unique, and if you use it only the first one will be parsed with document.getElementById() so that's why only the first one is toggled.
Solution:
Use a class instead of an id so you can attach the event to all the elements having this class.
And in your HTML code pass a reference to the clicked span with this to your toggleDescription() function and use it to find the relevant description inside it.
This is how should be your code:
for (var i = 0, len = mydata.texts.length; i < len; i++) {
list +="<li>"+"<div class='circle'></div>" +
"<span onclick='toggleDesc(this)'>"+ mydata.texts[i]["keyword"] +
"</span>"+
"<div class='descr'>"+mydata.texts[i]["description"]+"</div>";
+"</li>"
}
function toggleDesc(item) {
$(item).next('.descr').toggle();
}
And make sure you place the description div inside the li elemnt, because a list can contain only li as direct children.
edit:
it needs a css specification to hide by default:
.descr{
display:none;
}
Related
What I'd like to do is try to hide the parent div of the following (it would be hiding the div class called "eB cer") if h4 includes the word "bulk."
<div class="eB cer">
<h4>Bulk Load Files to CERs</h4>
<div class="tooltip"><b>Description: </b>You will add files to your CERs using the Bulk Load and Attribute Update Utility.<span class="tooltiptext">In this module you will learn how to add files to your CERs in bulk and modify any attributes as needed.</span>
</div>
<p><b>Link: </b>Bulk Load Files to CERs</p>
</div>
I have this and it's hiding the h4, but not the entire div.
var searched_string = "eB cer";
var foundmatch = [];
for(i=0; i < leftFilteredArray.length; i++){
if(leftFilteredArray[i].match(searched_string)){
foundmatch.push(leftFilteredArray[i]);
$("div h4:contains('" + searched_string +"')").hide();
}
Any suggestions what I'm doing wrong?
You can use indexOf() which returns the first index at which the specified string is found. Else it returns -1.
if($('.eB.cer>h4').text().toLowerCase().indexOf('bulk')!==-1)
$('.eB.cer').hide()
To recreate your situation I ended up looking at the jQuery line. Then I plugged it into the rest of the code. Here is what I got working.
var searched_string = "Bulk";
var foundmatch = [];
for(i=0; i < leftFilteredArray.length; i++){
if(leftFilteredArray[i].match(searched_string)){
foundmatch.push(leftFilteredArray[i]);
$("div h4:contains('" + searched_string +"')").parent().hide();
}
}
This line sets the text to lower case for less issues.
var searched_string = "Bulk";
var foundmatch = [];
for(i=0; i < leftFilteredArray.length; i++){
if(leftFilteredArray[i].match(searched_string)){
foundmatch.push(leftFilteredArray[i]);
// $("div h4:contains('" + searched_string +"')").parent().hide();
if( $(".eB.cer h4").html().toLowerCase().indexOf(searched_string.toLowerCase()) > -1) {
$(".eB.cer").hide();
}
}
}
The below images are all returned and displayed on page via this JavaScript/jQuery:
for(var j = 0; j < imageURLs.length; j++){
$('#imgs').append("<img src='" + imageURLs[j] + "'/>");
$('#username').append(Username[j]);
}
HTML:
<div id="imgs"></div>
I want the user to be able to click on any of the images and pass the image/username into a variable.
I thought I could use $this to select the individual images/usernames, but that just seems to return "imgs" each time. How can I use jQuery to select and capture the actual username/images? Do I need to use .mouseover() before adding the item?
$('imgs').click(function(event){
event.preventDefault();
var selectedFriend = $(this).attr("id");
console.log(selectedFriend);
});
});
Your selector is incorrect. When you are using $('imgs') jQuery is searching for imgs element which doesn't exists. Thus you need to change your selector to ID selector
Apart from above you are creating img element dynamically, thus you need to use Event Delegation
$('#imgs').on('click', 'img', function (event) {
event.preventDefault();
var selectedFriend = $(this).attr("id");
console.log(selectedFriend);
});
You could try having the append to define the onclick event too.
$('#imgs').append("<img src='" + imageURLs[j] + "' onclick='doStuff(this)'/>");
Try the following (not tested):
for(var j = 0; j < imageURLs.length; j++){
$('#imgs').append("<img src='" + imageURLs[j] + "' id='PUT_YOUR_UNIQUE_ID_HERE' />");
$('#username').append(Username[j]);
}
$('imgs').on('click', 'img', function(event){
event.preventDefault();
var selectedFriend = $(this).attr("id");
console.log(selectedFriend);
});
I have a dropdown that I want to be cloned and have a unique id. I managed to do it and it works on my website.
I am trying to make a "x" button to removed added clones and I can't get it to work.
The javascript:
var counter = 1;
function addInput(divName, template){
if (counter == 5) {
document.getElementById("add_more_text").remove();
} else {
var newdiv = document.createElement('div');
newdiv.innerHTML = document.getElementById(divName).innerHTML;
document.getElementById(template).appendChild(newdiv);
counter++;
}
var selectElements = document.querySelectorAll('select');
for (var i = 0; i < selectElements.length; i++){
selectElements[i].id = 'id-' + i;
selectElements[i].name = 'category' + i;
}
}
function removeInput(divName, template){
document.getElementById(template).removeChild(divName);
counter--;
}
The html:
<div id="template">
<select name="category0"><option>hi</option></select>
x
</div>
<div id="add_more"></div>
+ Add more
DEMO
Any help is much appreciated!
Simpler to modify remove function as follows:
function removeInput(obj) {
if (obj.parentNode.className == 'added') {
obj.parentNode.parentNode.removeChild(obj.parentNode);
counter--;
}
}
And have a link in template like this:
x
Class added is to distinguish new clones that can be removed:
newdiv.className = 'added';
Demo: http://jsfiddle.net/rjXXa/2/
in your onClick property
x
you are passing template and add_more
And in the handler function
function removeInput(divName, template){
the parameters are in a different order, so divName will contain 'template' and template will contain 'add_more'. Even if you fix this,
document.getElementById(template).removeChild(divName); // will throw error
because the div#add_more is not a child of div#template.
For fixing this, you need to pass a reference to the clicked element, like the following
x
and in your function
function removeInput(anchor){
var clone = anchor.parentNode; // div containing the anchor
if(clone.id!='template'){ // make sure we're not removing the original template
clone.parentNode.removeChild(clone);
counter--;
}
}
as in this Fiddle
Update
It's better to remove the add more option from display using css and make it visible later than removing/appending it in DOM, as follows
change the following in addInput() function
if (counter > 4) {
document.getElementById("add_more_text").style.display='none';
}
and in removeInput() function add
if (counter < 5) {
document.getElementById("add_more_text").style.display='block';
}
as in this Fiddle
I wanted to detect a span element while looping through a div element i.e.
<div class="example">
These are some <span id ="special" class="anime">special</span> words
that should be faded in one after the other.
</div>
using javascript i split the words and fade them in one by one i.e.
JS:
function doSomething(spanID) {
alert(spanID);
}
var $el = $(".example:first"), text = $.trim($el.text()),
words = text.split(" "), html = "";
for (var i = 0; i < words.length; i++) {
html += "<span>" + words[i] + ((i+1) === words.length ? "" : " ") + "</span>";
};
$el.html(html).children().hide().each(function(i){
// if special span is detected
// get the span id pass it to doSomething function
$(this).delay(i*200).fadeIn(700);
});
$el.find("span").promise().done(function(){
$el.text(function(i, text){
return $.trim(text);
});
});
working example is here: http://jsfiddle.net/6czap/5/
everything works, it just that i need to detect any special spans so i can do something with them, and then the for loop should carry on doing what it deos. thanks
Try the following:
var orig = $(".example:first").html()
$el.html(html).children().hide().each(function(i){
$(this).delay(i*200).fadeIn(700);
}).promise().done(function(){
$('.example:first').html(orig);
});
demo!
How do write a JavaScript conditional statement:
If an li tag has a class of "disabled" then add a class of "hide"
I am trying to add that class to an li tag that has this class. The li tag does not have an id.
First you have to get all li tags:
var lis = document.getElementsByTagName('li');
Then loop over them and perform the action:
for(var i = lis.length; i--;) {
var li = lis[i];
if(/\bdisabled\b/.test(li.className)) {
li.className += ' hide';
}
}
Reference: getElementsByTagName, className
Why can't we use getElementsByClassName?
Because it is not supported up to and including IE8.
But you could make a test whether the browser supports querySelectorAll:
if(typeof document.querySelectorAll === 'function') {
var lis = document.querySelectorAll('li.disabled');
for(var i = lis.length; i--;) {
lis[i].className += ' hide';
}
}
else {
// code from above
}
If you just have a reference to some li you only use the if class:
if(/\bdisabled\b/.test(element.className)) {
element.className += ' hide';
}
(In all cases, you could also add a further test to check whether the elements already have the hide class.)
Update:
In case you want to remove that class again, you can make a similar loop and use replace:
for(var i = lis.length; i--;) {
var li = lis[i];
li.className = li.className.replace(/\s*hide\s*/, '');
}
You should consider to make the add and remove class functions reusable so that you can use them with other classes too.
Using jQuery:
$('li.disabled').addClass('hide');
If you like jQuery:
$('li').hasClass('disabled').addClass('hide');
(explicitly mention hasClass just for reference sake and clarity, though li.disabled works just as well).
var items = document.getElementsByTagName('li');
for (var i = 0; i < items.length; i++){
var item = items[i];
if (/\bdisabled\b/.test(item.className)){
item.className += ' hide';
}
}
Hmm, ALL disabled LI elements need a class of hide? Can you not edit the CSS and hide them like that? Or use JavaScript to add a class to the HTML or BODY element and then in CSS, e.g.:
HTML.hide-disabled LI.disabled {/* properties to hide these elements */}