Hi I'd like some advice with what I'm trying to achieve.
I currently have this:
<div class="thumbnail">
<img src="thumbnail_1.jpg" />
</div>
For each .thumbnail I would like to prepend an index number with a span. Achieving this:
<div class="thumbnail">
<span class="index">001</span>
<img src="thumbnail_1.jpg" />
</div>
<div class="thumbnail">
<span class="index">002</span>
<img src="thumbnail_2.jpg" />
</div>
Thanks heaps.
$('div.thumbnail').each(function(i) {
var num = zeroPad(i + 1, 3);
$(this).prepend($('<span/>', {
'class': 'index',
'text': num
}));
});
The .each() method iterates over the elements and the callback receives the zero-based index of the element - so there you have your counter. The element itself is available as this (or as the second function argument, but you don't really need that). .prepend() inserts the passed element/string at the beginning of the element.
For a zeroPad function, simply search for "pad number javascript" in Google or here on SO and you'll find quite a few functions. Here's one for example:
function zeroPad(num, numZeros) {
var n = Math.abs(num);
var zeros = Math.max(0, numZeros - Math.floor(n).toString().length );
var zeroString = Math.pow(10,zeros).toString().substr(1);
if( num < 0 ) {
zeroString = '-' + zeroString;
}
return zeroString + n;
}
Along with the other solutions, I prefer the following (personal taste)
$('div.thumbnail').prepend(function (index) {
index = '000' + (index + 1);
return '<span class=index>' + index.substr(index.length - 3) + '</span>';
});
The prepend method takes a function that should return the html/DOM object that is to be prepended. See more in the docs.
Edit: As Michael Durrant commented, you might be wanting the numbers in the img's src attribute, not sequential numbers. If that is the case, the following should have you covered.
$('div.thumbnail > img').before(function () {
var index = this.src.match(/\d+/);
if (index === null) return;
index = '000' + index;
return '<span class=index>' + index.substr(index.length - 3) + '</span>';
});
Here, we add the span before the img elements. See the before documentation for more.
You can select all elements with the thumbnail class, loop over them, and prepend a span to each element containing the index.
// Select all elements with class .thumbnail and loop over them
$(".thumbnail").each(function(i, elm) {
// Prepend a index span to each element
$(elm).prepend('<span class="index">' + i + '</span>");
});
In this case the index will be number will be zero-based. If you like the index to start with 1, you can change the middle row to this: $(elm).prepend('<span class="index">' + (i + 1) + '</span>");
Try this:
$('.thumbnail').each(function(index) {
$('<span/>', {
'class': 'index',
text: "%03d".sprintf(index + 1)
}).prependTo(this);
});
Note that it won't add leading zeroes, as is.
I like the JSXT String.js module which would allow you to write "%03d".sprintf(index + 1)
Working demo at http://jsfiddle.net/SqQcs/1/
EDIT code has changed from first attempt - forgot that $(<tag>, { ... }) syntax only works in the jQuery constructor, and not in the generalised jQuery argument case.
Related
Here I'm trying to create a calling pad that reads a maximum of 10 numbers at a time, and displays the numbers as a maximum of 6 numbers in a row. It's working functionally. I want to remove the last number when the user presses the clear button.
I used $("#calling-pad").last().remove(); to try to remove the last number, but it removes the whole contents and doesn't allow to enter a new number. How can I fix it?
var key = 1;
$("#nine").click(function(){
if (p === 1) {
$("#mini-screen").css("display","none");
$("#number-screen").css("display","block");
if (key < 11) {
if ((key % 7) !== 0) {
$("#calling-pad").append("9");
key = key + 1;
}
else {
$("#calling-pad").append("<br>");
$("#calling-pad").append("9");
key = key + 1;
}
}
}
});
$("#inner-icon-one").click(function(){
if (p === 1) {
$("#mini-screen").css("display","none");
$("#number-screen").css("display","block");
if (key > 1) {
if ((key%6) !== 0) {
$("#calling-pad").last().remove();
key = key - 1;
if ( key === 1) {
$("#number-screen").css("display","none");
$("#mini-screen").css("display","block");
}
}
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span id="calling-pad"> </span>
You are just appending numbers to a span tag and are not really keeping track of user input.
$("#calling-pad").last().remove();
Is telling jQuery to remove the full contents because you are not inserting any child elements to the calling-pad span.
Therefore you could use an array to keep track of the users numbers or use a counter as I have shown below.
var totalInputs = 0;
$("#insert").on("click", function() {
totalInputs++;
var inputText = $("#input").val();
var id = "calling_" + totalInputs;
$("#calling-pad").append("<span id='" + id + "'>" + inputText + "</span>");
});
$("#remove").on("click", function() {
$("#calling_" + totalInputs).remove();
totalInputs--;
});
span {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input type="text" id="input" />
<button id="insert">Insert</button>
<div id="calling-pad">
</div>
<button id="remove">Remove last element</button>
Problem - Using 'last' instead of ':last-child'
The jQuery last method does not find child elements. Instead, given a collection of elements matching a selector, it filters that collection to include only the last element. Combining this with an id-selector (i.e. $("#element-id").last()) is always redundant, since $("#element-id") only matches a single element, and the resulting jQuery object is always of size 1. If there's only one element, it's always the last one.
Therefore $("#calling-pad").last().remove(); is effectively the same as saying $("#calling-pad").remove();.
Solution
Instead, when you're appending data to the #calling-pad element, ensure they're included as new elements (e.g. wrapped in <span></span> tags):
$('#calling-pad').append("<span>9</span>");
Then, when you want to remove the last element in the #calling-pad, you simply have to do this:
$('#calling-pad > span:last-child').remove();
This finds all span elements that are direct children of the #calling-pad, filters that to only include the last element (using :last-child), and then removes that element.
$("#calling-pad").contents().last().remove();
if ($("#calling-pad").contents().last().is("br")) {
$("#calling-pad").contents().last().remove();
}
As you're dealing with textNodes, you need to use .contents() - the <br> split them up so no need to parse things, and if you're deleting the last node, you need to delete the last break at the same time...
You need one line to remove last comment... no need to count ids ...
here is snippet ... Cheers Man
$("#insert").on("click", function() {
var inputText = $("#input").val();
$("#calling-pad").append("<span>" + inputText + "</br></span>");
});
$("#remove").click(function(){
$("#calling-pad").children("span:last").remove()
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input type="text" id="input" />
<button id="insert">Insert</button>
<div id="calling-pad">
</div>
<button id="remove">Remove last one</button>
I am making organizatoinal-chart-like structure. All divs have unique ID and a class that matches the ID of their parent (if they have one) like so:
<div id="title1" class="container"></div>
<div id="title4" class="container child title3"></div>
<div id="title3" class="container child title2"></div>
<div id="title2" class="container child title1"></div>
Idea is to order these in chart by absolutely positioning divs below their parent div, so they will be rendered in the right order.
Problem with the code below is that the $test_str returns as undefined, even if I pass .child as selector... and I am stuck.
$containers = $('.container');
$test = [];
for ( i = 0; i < $containers.length; i++ ) {
$test_str = $($containers[i]).nextAll('.' + $containers[i].id);
$test.push($test_str);
console.log($containers[i].id + ' is parent ' + $test[i].id);
//$test[i].id is returned as undefined;
}
Here is the fiddle
I would take an approach of just moving the divs using appendTo or insertAfter instead of trying to absolutely position them (which I think would be more difficult). This example uses appendTo since it creates an actual parent-child structure instead simply re-ordering.
$.each($('.container'), function(ind, val) {
$.each($('.' + val.id), function(i,v) {
console.log(val.id + ' is parent ' + v.id);
$(v).appendTo(val);
});
});
JSFiddle
If you output the $test_str to the console, the element info is under context, so you'll want to get the id from $test[i].context.id
$containers = $('.container');
$test = [];
for ( i = 0; i < $containers.length; i++ ) {
jQuery.fn.init();
$test_str = $($containers[i]).nextAll('.' + $containers[i].id);
$test.push($test_str);
console.log($containers[i].id + ' is parent ' + $test[i].context.id);
}
The problem you have is that nextAll() returns a sequence of items and you are treating it as a single item. The second problem you are probably going to run into is you are using nextAll() instead of siblings().
siblings
Description: Get the siblings of each element in the set of matched elements, optionally filtered by a selector.
nextAll() returns only successors at the same level and not true siblings.
Description: Get all following siblings of each element in the set of matched elements, optionally filtered by a selector.
Here is the code showing a way to get the result you want. I took out the intermediate array for the time being as it would just further complicate this.
$containers = $('.container');
$test = [];
for ( i = 0; i < $containers.length; i++ ) {
$test_str = $($containers[i]).siblings('.' + $containers[i].id);
console.log($test_str);
for(j = 0; j < $test_str.length; j++){
console.log($containers[i].id + ' is parent ' + $test_str[j].id);
}
}
Remember when dealing with JQuery that most of the time the functions will return a sequence of items instead of a single item, even if there is only one match.
What I'm trying to do is add a [+] or [-] sign to an expandable heading so that once the user clicks on the heading, its content part will be shown and its sign part will change from + to - and vice versa. Since there are multiple headings, I used jQuery's next(). So far the .content toggling works well, but for some reason the sign is not changing.
<script type="text/javascript">
jQuery(document).ready(function() {
jQuery(".content").hide();
jQuery(".heading").click(function()
{
jQuery(this).next(".content").toggle();
if (jQuery(this).next(".sign").text()=="[+]")
{jQuery(this).next(".sign").text("[-]");}
else
{jQuery(this).next(".sign").text("[+]");}
});
});
</script>
for (int i = 0; i < nodes.getLength(); i++)
{
Element element = (Element) nodes.item(i);
NodeList title = element.getElementsByTagName("Title");
Element ttl = (Element) title.item(0);
String linkTitle = getCharacterDataFromElement(ttl);
htmlReturn += "<a href='#' class='heading'><h4>" + linkTitle + " <span class='sign'>[+]</span></h4></a>";
htmlReturn += "<div class='content'>";
...
}
Because the sign is a descendant element of the heading, not a sibling, use find instead of next:
var sign = jQuery(this).find(".sign");
sign.text(sign.text() === "[+]" ? "[−]" : "[+]");
// Note: A minus sign (−) has the same width as a plus sign (+),
// whereas a hyphen (-) is typically narrower.
if (jQuery(".sign").text()=="[+]")
{jQuery(".sign").text("[-]");}
else
{jQuery(".sign").text("[+]");}
Well, next() only gets the immediate sibling. Try using closest() instead.
How could I change the text below so that the text within it has a number appended to it.
<div class="right">This is some text</div>
<div class="right">This is some text</div>
<div class="right">This is some text</div>
So the code above would become,
This is some text
This is some text
This is some text
you should use an ordered list... ol
or else you will need use css and add the content property your selector with the :after pseudo element.
How about the following?
$("div.right").each(function(i){
$(this).prepend((i + 1) + ". ");
});
UPDATE:
Here is one way that should work.
"number" is a custom element (it can be anything you want) that will/should be ignored by browsers.
$("div.right").each(function(i){
$(this).find("number").remove().end()
.prepend("<number>(i + 1) + ". </number>");
});
OR use the following which is probably a little slower but semantically correct...
$("div.right").each(function(i){
$(this).find("span.number").remove().end()
.prepend("<span class='number'>" + (i + 1) + ". </span>");
});
OR an even better way would be to prepend span.number before your first drag:
$(function(){ // document ready...
// caching the "numbers" will only work if you use the DOM
// for updating div position (like jQuery's "append()", "prepend()", "before()", and "after()") and not "innerHTML" or "html()"
var numbers = $("div.right").each(function(i){
$(this).prepend("<span class='number'>" + (++i) + "</span>. ");
}).find("span.number");
function dragEnd(){
// do your drag end stuff here...
numbers.each(function(i){
this.innerHTML = ++i;
});
)};
});
This is really an elaboration on another comment. I can't format code in a comment, I guess. You could use jQuery core's each:
$('div.right').each(function(ii){
html = $(this).html();
$(this).html(ii + '. ' + html);
});
jQuery selectors are your friend...
Get your stuff and loop on through something like this:
texts = $("div.right");
for(i = 0;i < texts.length;i++)
{
node = $(texts[i]);
content = node.html();
number = i + 1;
node.html(number + ". " + content);
}
Update: Jeez, last time post untested code straight off the dome here (disclaimer: not actually the last time). In the interest of correctness, I've updated it to at least run (and work!) if you still want to do it this way. Although I admit the other solutions are cleaner and more elegant.
Does this have to be done dynamically through jquery? Can't you just combine all that text into one div and then make a ordered list around it?
Using [] notation with a result set will give you the raw DOM element which does not have the html() function. Use the eq() function to get each element wrapped in a jQuery object.
You can also use each() as mentioned above, but I prefer straight 'for loops' so I don't have to adjust for 'this' if I'm in an event handler.
var texts = $("div.right");
var elem;
for(i = 1; i < texts.length; i++) {
elem = texts.eq(i);
html = elem.html();
elem.html(i + '. ' + html);
}
I have an HTML element with a large collection of unordered lists contained within it. I need to clone this element to place elsewhere on the page with different styles added (this is simple enough using jQuery).
$("#MainConfig").clone(false).appendTo($("#smallConfig"));
The problem, however, is that all the lists and their associated list items have IDs and clone duplicates them. Is there an easy way to replace all these duplicate IDs using jQuery before appending?
If you need a way to reference the list items after you've cloned them, you must use classes, not IDs. Change all id="..." to class="..."
If you are dealing with legacy code or something and can't change the IDs to classes, you must remove the id attributes before appending.
$("#MainConfig").clone(false).find("*").removeAttr("id").appendTo($("#smallConfig"));
Just be aware that you don't have a way to reference individual items anymore.
Since the OP asked for a way to replace all the duplicate id's before appending them, maybe something like this would work. Assuming you wanted to clone MainConfig_1 in an HTML block such as this:
<div id="smallConfig">
<div id="MainConfig_1">
<ul>
<li id="red_1">red</li>
<li id="blue_1">blue</li>
</ul>
</div>
</div>
The code could be something like the following, to find all child elements (and descendants) of the cloned block, and modify their id's using a counter:
var cur_num = 1; // Counter used previously.
//...
var cloned = $("#MainConfig_" + cur_num).clone(true, true).get(0);
++cur_num;
cloned.id = "MainConfig_" + cur_num; // Change the div itself.
$(cloned).find("*").each(function(index, element) { // And all inner elements.
if(element.id)
{
var matches = element.id.match(/(.+)_\d+/);
if(matches && matches.length >= 2) // Captures start at [1].
element.id = matches[1] + "_" + cur_num;
}
});
$(cloned).appendTo($("#smallConfig"));
To create new HTML like this:
<div id="smallConfig">
<div id="MainConfig_1">
<ul>
<li id="red_1">red</li>
<li id="blue_1">blue</li>
</ul>
</div>
<div id="MainConfig_2">
<ul>
<li id="red_2">red</li>
<li id="blue_2">blue</li>
</ul>
</div>
</div>
$("#MainConfig")
.clone(false)
.find("ul,li")
.removeAttr("id")
.appendTo($("#smallConfig"));
Try that on for size. :)
[Edit] Fixed for redsquare's comment.
I use something like this:
$("#details").clone().attr('id','details_clone').after("h1").show();
This is based on Russell's answer but a bit more aesthetic and functional for forms.
jQuery:
$(document).ready(function(){
var cur_num = 1; // Counter
$('#btnClone').click(function(){
var whatToClone = $("#MainConfig");
var whereToPutIt = $("#smallConfig");
var cloned = whatToClone.clone(true, true).get(0);
++cur_num;
cloned.id = whatToClone.attr('id') + "_" + cur_num; // Change the div itself.
$(cloned).find("*").each(function(index, element) { // And all inner elements.
if(element.id)
{
var matches = element.id.match(/(.+)_\d+/);
if(matches && matches.length >= 2) // Captures start at [1].
element.id = matches[1] + "_" + cur_num;
}
if(element.name)
{
var matches = element.name.match(/(.+)_\d+/);
if(matches && matches.length >= 2) // Captures start at [1].
element.name = matches[1] + "_" + cur_num;
}
});
$(cloned).appendTo( whereToPutIt );
});
});
The Markup:
<div id="smallConfig">
<div id="MainConfig">
<ul>
<li id="red_1">red</li>
<li id="blue_1">blue</li>
</ul>
<input id="purple" type="text" value="I'm a text box" name="textboxIsaid_1" />
</div>
</div>
FWIW, I used Dario's function, but needed to catch form labels as well.
Add another if statement like this to do so:
if(element.htmlFor){
var matches = element.htmlFor.match(/(.+)_\d+/);
if(matches && matches.length >= 2) // Captures start at [1].
element.htmlFor = matches[1] + "_" + cur_num;
}
If you will have several similar items on a page, it is best to use classes, not ids. That way you can apply styles to uls inside different container ids.
I believe this is the best way
var $clone = $("#MainConfig").clone(false);
$clone.removeAttr('id'); // remove id="MainConfig"
$clone.find('[id]').removeAttr('id'); // remove all other id attributes
$clone.appendTo($("#smallConfig")); // add to DOM.
Here is a solution with id.
var clone = $("#MainConfig").clone();
clone.find('[id]').each(function () { this.id = 'new_'+this.id });
$('#smallConfig').append(clone);
if you want dynamically set id, you can use counter instead of 'new_'.