I have implemented a really simple jQuery spoiler functionality using the following code:
HTML:
<a href="" onclick="return false" class="spoiler" content="spoiled content">
Reveal spoiler
</a>
jQuery / Javascript:
$('a.spoiler').click(function(){
$text = "" + $(this).attr("content") + "";
$(this).replaceWith($text);
});
Basically, I just want the spoiler's content attribute to swap with the text in between the tags. It works for the first click, however it does not swap back when clicked again.
Is there any way for me to implement this in a way where it will indefinitely swap the content?
Thanks!
Simply use
$('a.spoiler').click(function(){
var text = $(this).text();
var content = $(this).attr("content");
$(this).text(content).attr("content", text)
});
DEMO
Otherwise, You need to use Event Delegation using .on() delegated-events approach as you are using replaceWith which is remove elemnent with which event was binded.
$(document).on('click','a.spoiler',function(){
$text = "" + $(this).attr("content") + "";
$(this).replaceWith($text);
});
DEMO
You can use this
$('a.spoiler').click(function () {
$(this).text(function (_, t) {
return t.trim() == "Reveal spoiler" ? $(this).attr('content') : "Reveal spoiler";
});
});
DEMO
Change your code to-
$(document).on('click','a.spoiler',function(){
$text = "" + $(this).attr("content") + "";
$(this).replaceWith($text);
});
If new HTML is being injected into the page,use delegated events to attach an event handler
Edit-
DEMO
$('a.spoiler').click(function(){
$text = $(this).attr("content")
$(this).attr("content",$(this).text()).text($text);
});
Related
I found a lot of info about this, but I haven't foundanything that could help me yet.
My problem is that I have got a div with its id and it supposes to be a container (#cont_seguim).
I have a menu on the right side which contains circles (made by css and filled with text), like following:
<div class="circle_menu b">
<div class="text_menu n">ECO</div>
</div>
where b and n are the format for background and text.
When I click a circle, this one must be added to the container (notice that each circle has got its own text), but I can't get that.
I made and array and used alert() to test that click works, and it does, but append() doesn't even work to print text, and I don't know why.
<script type="text/javascript">
var arrayS = new Array();
$(document).ready(function() {
$(".circulo_menu").click(function() {
var text = $(this).text();
alert("calling " + text);
$("#cont_seguim").append(text);
});
return text;
});
</script>
Thank you for your responses!
Your code seems to work fine (if you fix the different class name used in html vs script circulo_menu vs circle_menu)
Demo at http://jsfiddle.net/7jbUj/
To add the whole circle append the whole element and not its text by using .append(this)
$(".circle_menu").click(function() {
$("#cont_seguim").append(this);
});
Demo at http://jsfiddle.net/7jbUj/1/
To add a copy of the circle, so you can add multiple of them use the .clone() first..
$(".circle_menu").click(function() {
var clone = $(this).clone(false);
$("#cont_seguim").append(clone);
});
Demo at http://jsfiddle.net/7jbUj/3/
Inside the click handler, this refers to the clicked element. And since you bind the click handler on the circle_menu element, this refers to that. You can use it directly for the appending or clone it to make a copy first..
unable to understand properly, hope below one can help you.
<script type="text/javascript">
$(document).ready(function() {
$(".circulo_menu").click(function() {
var myText = $(this).html();
alert("calling " + myText);
$("#cont_seguim").html(myText);
});
});
</script>
make sure classname and id name will remain same as html
Try using html() instead of text().
Try this: Demo
HTML:
<div class="circle_menu b">
<div class="text_menu n">ECO</div>
</div>
<div id="cont_seguim"></div>
Javascript:
$(document).ready(function() {
$(".circle_menu").click(function() {
var text = $(this).html();
console.log("calling " + text);
$("#cont_seguim").append(text);
});
});
Try this:
$( ".container" ).append( $( "<div>" ) );
source
use
$("#container").append($("<div/>", {id:"newID",text:"sometext"}));
You could try
<script type="text/javascript">
var arrayS = new Array();
$(document).ready(function() {
$(".circulo_menu").click(function() {
var text = $(this).text();
alert("calling " + text);
$("#cont_seguim").append($(this).html());
});
return text;
});
</script>
By this way the clicked circle element get added to div
I'm creating anchor tags dynamically and I want them to call a function that has a set parameter for each one.
Example:
<div class="AnchorHolder">
<a onclick="someFunction(1)">someText</a>
<a onclick="someFunction(2)">someText</a>
<a onclick="someFunction(3)">someText</a>
</div>
I've tried
$("#AnchorHolder").append("<a>" + someText + "</a>").click(function (e) {
someFunction(someIntVariable);
});
but instead connects all of the anchors to the IntVariables current value, whereas I wanted the previous ones.
How can I accomplish this?
Well, I would suggest you to try data attributes. As far I know they are made for that porpuse. See:
$("#AnchorHolder").append("<a href='#' data-myvar='" + someIntVariable + "'>" + someText + "</a>");
// Keep the event binding out of any loop, considering the code above will be called more than once...
$("#AnchorHolder").on('click', 'a', function (e) {
alert($(this).data("myvar"));
});
Fiddle
If you just want the click on the new element, tack it onto that element, and not on the #AnchorHolder element:
var newAnchor = $("<a>" + someText + "</a>").click(function (e) {
someFunction(someIntVariable);
});
$("#AnchorHolder").append(newAnchor);
Or, alternatively to get each <a> to call the someFunction with their postion-inside-the-div:
$("#AnchorHolder a").each(function(idx) {
var a = $(this);
a.click(function() { someFunction(idx); });
});
You can always create a html element as following
$('<a>').attr("onclick","fun('hi')").html('Some text').appendTo("#AnchorHolder");
Hope this helps
I want to use jquery append() to add content to a textbox without having to consider newline characters that show up in the html markup and indent the content. How do I get jquery to ignore newline characters in regards to textarea?
<div id = "content-frame">
<div id = "remove-frame">
<div id = "content">
here is the content, click this content
</div>
</div>
</div>
$("#remove-frame").click(function () {
var divContents = $("#content").text();
$("#content").remove();
$("#remove-frame").append(function() {
return '<textarea id = "edit-textarea">' + divContents + "</textarea>";
});
});
http://jsfiddle.net/8KA8q/3/
You missed to trim the content value. Also you can use JQuery.trim() to keep browser compatibility. Try to modify your code as bellow:
$("#remove-frame").click(function () {
var divContents = $("#content").text().trim();
$("#content").remove();
$("#remove-frame").append(function() {
return '<textarea id = "edit-textarea">' + divContents + "</textarea>";
});
});
I think what you want is .prepend() instead of .append();
append places it as a last child, prepend as a first child.
also if that doesnt work play with .appendto() and .prependto().
Good luck
Take a Look
I have the following HTML snippet:
<span class="target">Change me <a class="changeme" href="#">now</a></span>
I'd like to change the text node (i.e. "Change me ") inside the span from jQuery, while leaving the nested <a> tag with all attributes etc. intact. My initial huch was to use .text(...) on the span node, but as it turns out this will replace the whole inner part with the passed textual content.
I solved this with first cloning the <a> tag, then setting the new text content of <span> (which will remove the original <a> tag), and finally appending the cloned <a> tag to my <span>. This works, but feels such an overkill for a simple task like this. Btw. I can't guarantee that there will be an initial text node inside the span - it might be empty, just like:
<span class="target"><a class="changeme" href="#">now</a></span>
I did a jsfiddle too. So, what would be the neat way to do this?
Try something like:
$('a.changeme').on('click', function() {
$(this).closest('.target').contents().not(this).eq(0).replaceWith('Do it again ');
});
demo: http://jsfiddle.net/eEMGz/
ref: http://api.jquery.com/contents/
Update:
I guess I read your question wrong, and you're trying to replace the text if it's already there and inject it otherwise. For this, try:
$('a.changeme').on('click', function() {
var
$tmp = $(this).closest('.target').contents().not(this).eq(0),
dia = document.createTextNode('Do it again ');
$tmp.length > 0 ? $tmp.replaceWith(dia) : $(dia).insertBefore(this);
});
Demo: http://jsfiddle.net/eEMGz/3/
You can use .contents():
//set the new text to replace the old text
var newText = 'New Text';
//bind `click` event handler to the `.changeme` elements
$('.changeme').on('click', function () {
//iterate over the nodes in this `<span>` element
$.each($(this).parent().contents(), function () {
//if the type of this node is undefined then it's a text node and we want to replace it
if (typeof this.tagName == 'undefined') {
//to replace the node we can use `.replaceWith()`
$(this).replaceWith(newText);
}
});
});
Here is a demo: http://jsfiddle.net/jasper/PURHA/1/
Some docs for ya:
.contents(): http://api.jquery.com/contents
.replaceWith(): http://api.jquery.com/replacewith
typeof: https://developer.mozilla.org/en/JavaScript/Reference/Operators/typeof
Update
var newText = 'New Text';
$('a').on('click', function () {
$.each($(this).parent().contents(), function () {
if (typeof this.tagName == 'undefined') {
//instead of replacing this node with the replacement string, just replace it with a blank string
$(this).replaceWith('');
}
});
//then add the replacement string to the `<span>` element regardless of it's initial state
$(this).parent().prepend(newText);
});
Demo: http://jsfiddle.net/jasper/PURHA/2/
You can try this.
var $textNode, $parent;
$('.changeme').on('click', function(){
$parent = $(this).parent();
$textNode= $parent.contents().filter(function() {
return this.nodeType == 3;
});
if($textNode.length){
$textNode.replaceWith('Content changed')
}
else{
$parent.prepend('New content');
}
});
Working demo - http://jsfiddle.net/ShankarSangoli/yx5Ju/8/
You step out of jQuery because it doesn't help you to deal with text nodes. The following will remove the first child of every <span> element with class "target" if and only if it exists and is a text node.
Demo: http://jsfiddle.net/yx5Ju/11/
Code:
$('span.target').each(function() {
var firstChild = this.firstChild;
if (firstChild && firstChild.nodeType == 3) {
firstChild.data = "Do it again";
}
});
This is not a perfect example I guess, but you could use contents function.
console.log($("span.target").contents()[0].data);
You could wrap the text into a span ... but ...
try this.
http://jsfiddle.net/Y8tMk/
$(function(){
var txt = '';
$('.target').contents().each(function(){
if(this.nodeType==3){
this.textContent = 'done ';
}
});
});
You can change the native (non-jquery) data property of the object. Updated jsfiddle here: http://jsfiddle.net/elgreg/yx5Ju/2/
Something like:
$('a.changeme3').click(function(){
$('span.target3').contents().get(0).data = 'Do it again';
});
The contents() gets the innards and the get(0) gets us back to the original element and the .data is now a reference to the native js textnode. (I haven't tested this cross browser.)
This jsfiddle and answer are really just an expanded explanation of the answer to this question:
Change text-nodes text
$('a.changeme').click(function() {
var firstNode= $(this).parent().contents()[0];
if( firstNode.nodeType==3){
firstNode.nodeValue='New text';
}
})
EDIT: not sure what layout rules you need, update to test only first node, otherwise adapt as needed
Goal:
Using jQuery, I'm trying to replace all the occurrences of:
<code> ... </code>
with:
<pre> ... </pre>
My solution:
I got as far as the following,
$('code').replaceWith( "<pre>" + $('code').html() + "</pre>" );
The problem with my solution:
but the issues is that it's replacing everything between the (second, third, fourth, etc)"code" tags with the content between the first "code" tags.
e.g.
<code> A </code>
<code> B </code>
<code> C </code>
becomes
<pre> A </pre>
<pre> A </pre>
<pre> A </pre>
I think I need to use "this" and some sort of function but I'm afraid I'm still learning and don't really understand how to piece a solution together.
You can pass a function to .replaceWith [docs]:
$('code').replaceWith(function(){
return $("<pre />", {html: $(this).html()});
});
Inside the function, this refers to the currently processed code element.
DEMO
Update: There is no big performance difference, but in case the code elements have other HTML children, appending the children instead of serializing them feels to be more correct:
$('code').replaceWith(function(){
return $("<pre />").append($(this).contents());
});
This is much nicer:
$('code').contents().unwrap().wrap('<pre/>');
Though admittedly Felix Kling's solution is approximately twice as fast:
It's correct that you'll always obtain the first code's contents, because $('code').html() will always refer to the first element, wherever you use it.
Instead, you could use .each to iterate over all elements and change each one individually:
$('code').each(function() {
$(this).replaceWith( "<pre>" + $(this).html() + "</pre>" );
// this function is executed for all 'code' elements, and
// 'this' refers to one element from the set of all 'code'
// elements each time it is called.
});
Try this:
$('code').each(function(){
$(this).replaceWith( "<pre>" + $(this).html() + "</pre>" );
});
http://jsfiddle.net/mTGhV/
How about this?
$('code').each(function () {
$(this).replaceWith( "<pre>" + $(this).html() + "</pre>" );
});
Building up on Felix's answer.
$('code').replaceWith(function() {
var replacement = $('<pre>').html($(this).html());
for (var i = 0; i < this.attributes.length; i++) {
replacement.attr(this.attributes[i].name, this.attributes[i].value);
}
return replacement;
});
This will reproduce the attributes of the code tags in the replacement pre tags.
Edit: This will replace even those code tags that are inside the innerHTML of other code tags.
function replace(thisWith, that) {
$(thisWith).replaceWith(function() {
var replacement = $('<' + that + '>').html($(this).html());
for (var i = 0; i < this.attributes.length; i++) {
replacement.attr(this.attributes[i].name, this.attributes[i].value);
}
return replacement;
});
if ($(thisWith).length>0) {
replace(thisWith, that);
}
}
replace('code','pre');
As of jQuery 1.4.2:
$('code').replaceWith(function(i,html) {
return $('<pre />').html(html);
});
You can then select the new elements:
$('pre').css('color','red');
Source: http://api.jquery.com/replaceWith/#comment-45493689
jsFiddle: http://jsfiddle.net/k2swf/16/
If you were using vanilla JavaScript you would:
Create the new element
Move the children of old element into the new element
Insert the new element before the old one
Remove the old element
Here is jQuery equivalent of this process:
$("code").each(function () {
$("<pre></pre>").append(this.childNodes).insertBefore(this);
$(this).remove();
});
Here is the jsperf URL:
http://jsperf.com/substituting-one-tag-for-another-with-jquery/7
PS: All solutions that use .html() or .innerHTML are destructive.
Another short & easy way:
$('code').wrapInner('<pre />').contents();
All answers given here assume (as the question example indicates) that there are no attributes in the tag. If the accepted answer is ran on this:
<code class='cls'>A</code>
if will be replaced with
<pre>A</pre>
What if you want to keep the attributes as well - which is what replacing a tag would mean... ? This is the solution:
$("code").each( function(){
var content = $( "<pre>" );
$.each( this.attributes, function(){
content.attr( this.name, this.value );
} );
$( this ).replaceWith( content );
} );
$('code').each(function(){
$(this).replaceWith( "<pre>" + $(this).html() + "</pre>" );
});
Best and clean way.
You could use jQuery's html function. Below is a sample the replaces a code tag with a pre tag while retaining all of the attributes of the code.
$('code').each(function() {
var temp=$(this).html();
temp=temp.replace("code","pre");
$(this).html(temp);
});
This could work with any set of html element tags that needed to be swapped while retaining all the attributes of the previous tag.
Made jquery plugin, maintaining attributes also.
$.fn.renameTag = function(replaceWithTag){
this.each(function(){
var outerHtml = this.outerHTML;
var tagName = $(this).prop("tagName");
var regexStart = new RegExp("^<"+tagName,"i");
var regexEnd = new RegExp("</"+tagName+">$","i")
outerHtml = outerHtml.replace(regexStart,"<"+replaceWithTag)
outerHtml = outerHtml.replace(regexEnd,"</"+replaceWithTag+">");
$(this).replaceWith(outerHtml);
});
return this;
}
Usage:
$('code').renameTag('pre')