How to replace anchor element with the innerHTML of itself - javascript

I try to write a script based on JavaScript for replacing the current selected anchor element with it's inner HTML.
You can also find a simple running example in JSFiddle. To run the example, click on the first link, and the click the button.
So, for example, if I have the following HTML:
<p>
Wawef awef <em>replace</em> <strong>me</strong>
falwkefi4hjtinyoh gf waf eerngl nregsl ngsekdng selrgnlrekg slekngs ekgnselrg nselrg
<a href="http://www.anothersite.com/>replace me</a> klserng sreig klrewr
</p>
and I like when I click on some of the two anchors to remove the anchor with it's inner HTML. This mean, that if I click on the first anchor element, and click the appropriate button to replace the anchor the result should be like that:
<p>
Wawef awef <em>replace</em> <strong>me</strong> falwkefi4hjtinyoh gf waf eerngl
nregsl ngsekdng selrgnlrekg slekngs ekgnselrg nselrg <a href="http://www.anothersite.com/>replace me</a>
klserng sreig klrewr
</p>
My JavaScript code for this functionality is the following:
// Start tracking the click event on the document
document.addEventListener(
'click',
function(event)
{
// If right click, return
if(event.button == 2)
{
return;
}
// Get the current clicked document element
var link = event.target;
while(link && !(link instanceof HTMLAnchorElement))
{
link = link.parentNode;
}
// Get the element with ID wpf-remove-element-now
var clickedLink = document.getElementById("wpf-remove-element-now");
// If the element exists
if(clickedLink !== null)
{
// By executing this code, I am ensuring that I have only
// one anchor element in my document with this ID
// Remove the id attribute
clickedLink.removeAttribute('id');
}
// If ther is no link element
if(!link)
{
// Disable my "unlink" button
editor.commands.customunlinkcmd.disable();
// and return
return;
}
event.preventDefault();
event.stopPropagation();
// If the user has clickde on an anchor element then
// enable my "unlink" button in order to allow him to
// to replace the link if he like to.
editor.commands.customunlinkcmd.enable();
// Set the id attribute of the current selected anchor
// element to wpf-remove-element-now
link.setAttribute('id', 'wpf-remove-element-now');
}
);
var $unlink_button = document.getElementById('unlink');
$unlink_button.addEventListener(
'click',
function(event)
{
// Get the element with ID wpf-remove-element-now
var link = document.getElementById("wpf-remove-element-now");
// Create a new text node that contains the link inner HTML
var text = document.createTextNode(link.innerHTML);
// Make the replacement
link.parentNode.replaceChild(text, link);
}
);
Everything until now is correct, appart of the replacement of the link. I have try the above code, but the result I get is like the following one:
Wawef awef <em>replace</em> <strong>me</strong> falwkefi4hjtinyoh gf waf eerngl
nregsl ngsekdng selrgnlrekg slekngs ekgnselrg nselrg replace me klserng sreig klrewr
I mean the anchor is replaced with the text form of the inner HTML and not with the HTML form of the inner HTML.
So the question is, how can I do this kind of replacement.

You're creating a text node, so whatever you put in it will be interpreted as text. Instead, since you have the replacement tags predefined, you should create actual DOM elements to replace it with. Something like this could work: JSFiddle
var em_elem = document.createElement('em');
em_elem.appendChild(document.createTextNode("replace"));
var strong_elem = document.createElement('strong');
strong_elem.appendChild(document.createTextNode("me"));
var container_span = document.createElement('span');
container_span.appendChild(em_elem);
container_span.appendChild(strong_elem);
// Make the replacement
link.parentNode.replaceChild(container_span, link);

The answer was much simpler that I thought. I placed the solution below for anybody that need an equivalent solution :) :
$unlink_button.addEventListener(
'click',
function(event)
{
// Get the element with ID wpf-remove-element-now
var link = document.getElementById("wpf-remove-element-now");
// By this code you replace the link outeHTML (the link itself) with
// the link innerHTML (anything inside the link)
link.outerHTML = link.innerHTML;
}
);
Here you can find the running solution : JSFiddle
Note: The inspiration for this solution found in the web page.

Related

Any reason why jquery .click() wouldent target an a tag?

I am stumped as to why my query .click() is not working. I am trying to change the href tag on an a element, before it goes to the next page.
here is my jquery
$('.individualFormSections').click(function() {
var formSectionTitle = $(this).siblings('div').text(); // gets section title that was clicked
console.log(formSectionTitle);
assetConfigIdForURL = assetConfigIdForURL.replace(/\s+/g,'-');
woTypeCodeForURL = woTypeCodeForURL.replace(/\s+/g,'-');
woMaintTypeCode = woMaintTypeCode.replace(/\s+/g,'-');
formSectionTitle = formSectionTitle.replace(/\s+/g,'-');
// Change href dynamically to set url parameters
$(this).attr("href",'airSystem.html?insp_asset_config_id='+assetConfigIdForURL+'&wo_type_code='+woTypeCodeForURL+'&wo_maint_type_code='+woMaintTypeCode+'&formSection='+formSectionTitle+'&wo_id='+woIdForURL+'');
});
Here is the html
<a class="individualFormSections" href="">
<img class="bus-form-img" src="pull-up.jpg" alt="Trolltunga Norway">
</a>
<div class="desc" id="bodyDamageDesc">AirSystem</div>
I also tried doing a simple alert and its not even targeting the a tag. My javascript link is set up correctly.
A little background, the html is getting generated dynamically from a previous javascript function. When I use chrome developer tools, all the html shows just fine. Any ideas on what could be causing this?
Always use prevent default in such cases
$('.individualFormSections').click(function(e) {
e.preventDefault();
var formSectionTitle = $(this).siblings('div').text(); // gets section title that was clicked
console.log(formSectionTitle);
assetConfigIdForURL = assetConfigIdForURL.replace(/\s+/g,'-');
woTypeCodeForURL = woTypeCodeForURL.replace(/\s+/g,'-');
woMaintTypeCode = woMaintTypeCode.replace(/\s+/g,'-');
formSectionTitle = formSectionTitle.replace(/\s+/g,'-');
// Change href dynamically to set url parameters
$(this).attr("href",'airSystem.html?insp_asset_config_id='+assetConfigIdForURL+'&wo_type_code='+woTypeCodeForURL+'&wo_maint_type_code='+woMaintTypeCode+'&formSection='+formSectionTitle+'&wo_id='+woIdForURL+'');
});
Change to this.
$('.individualFormSections').click(function(e) {
e.preventDefault();
var formSectionTitle = $(this).siblings('div').text(); // gets section title that was clicked
console.log(formSectionTitle);
assetConfigIdForURL = assetConfigIdForURL.replace(/\s+/g,'-');
woTypeCodeForURL = woTypeCodeForURL.replace(/\s+/g,'-');
woMaintTypeCode = woMaintTypeCode.replace(/\s+/g,'-');
formSectionTitle = formSectionTitle.replace(/\s+/g,'-');
// Change href dynamically to set url parameters
$(this).attr("href",'airSystem.html?insp_asset_config_id='+assetConfigIdForURL+'&wo_type_code='+woTypeCodeForURL+'&wo_maint_type_code='+woMaintTypeCode+'&formSection='+formSectionTitle+'&wo_id='+woIdForURL+'');
});

How to execute event handler only once in Javascript?

I'm creating button which allows to enter post section. I'm checking if the body has class 'logged-in'. If test is false I want to create div container for message " You have to logi in" and append it to my section. My problem: Everytime when I click this button, new node is appended.
- How to invoke handler only once ?
if( !isOnline ) {
e.preventDefault();
var divForLog = document.createElement('div'),
linkElement = document.createElement('a');
linkElement.setAttribute('href', 'http://domain/login');
linkElement.text = "log in"
divForLog.innerHTML = "You have to ";
divForLog.appendChild(linkElement);
document.getElementById('last_questions').appendChild(divForLog);
}
There are several potential solutions, but I'll only list a couple here.
"Global"
Create a variable var loginShown in the scope where the handler is created. Then, change the ! isOnline check to ! isOnline && ! loginShown in the if statement, and set loginShown = true once you've appended the div.
Fiddle the DOM
Depending on the other content of #last_questions you can simply test whether or not the login element has already been appended using:
if ( ! document.getElementById('last_questions').querySelector('div > a[href="http://domain/login"]' ) ) {
...
}
Failing that, you can do as #NewToJS mentioned in the comments and add an attribute to the parent (once the div has been appended) which you can test for, such as an ID or data- attribute.
Unbind the Event
Easier if you're using jQuery, as mentioned by #Pawel you can simply unbind the event once the div has been appended. Probably the cleanest solution, but also trickier to implement. It also depends what else the handler is doing.
Try to set an attribute id to your div (container in my example) and when the user click check if the element with id already exist in document, if not add it :
if( !isOnline && document.getElementById('container').length==0) {
e.preventDefault();
var divForLog = document.createElement('div'),
linkElement = document.createElement('a');
linkElement.setAttribute('href', 'http://domain/login');
linkElement.text = "log in"
divForLog.innerHTML = "You have to ";
divForLog.appendChild(linkElement);
divForLog.setAttribute('id', 'container'); //Add id attribute
document.getElementById('last_questions').appendChild(divForLog);
}
Hope this helps.
If you're using jQuery something you could do(from the documentation .one | jQuery).
$("#button" ).one( "click", function() {
var divForLog = document.createElement('div'),
linkElement = document.createElement('a');
linkElement.setAttribute('href', 'http://domain/login');
linkElement.text = "log in"
divForLog.innerHTML = "You have to ";
divForLog.appendChild(linkElement);
document.getElementById('last_questions').appendChild(divForLog);
});
However another way I could think of would be to use jQuery's
$('#last_questions').html(divForLog);
Update
If thats not an option(most likely, as the #last_questions div may contain other stuff), you can create a <div id="log-in-alert"></div> which will live inside the #last_questions and only replace the html in this
Hope I was able to help??

How can I insert a div at the location where a user clicks inside a div?

Suppose I have a div that contains a sentence such as the one listed below:
<div class="sentence">This is a sentence</div>
I am trying to create a function/event handler that will recognize when the user clicks on the text inside the <div>. But, when they click inside the <div> the function needs to know exactly where they clicked so I can insert a <span> at that location. For example, if the user clicks in between the letters 'n' and 't' in the word 'sentence', then I want to insert a <span> there so I end up with
<div class="sentence">This is a sen<span>test</span>tence</div>
Something like this:
$('.sentence').on('click', function (e) {
var to_insert = '<span>test</span>';
// determine exactly where inside the div I clicked
// insert 'to_insert' at that location
});
Any ideas?
You can to get the position of the click in a string, using window.getSelection().anchorOffset
JS
$('.sentence').on('click', function (e) {
var to_insert = 'test';
var anchorOffset = window.getSelection().anchorOffset;
var resultHtml = $(this).html().substring(0, anchorOffset) + to_insert + $(this).html().substring(anchorOffset);
$(this).html(resultHtml);
});
DEMO

How to check if an element with id exists or not in jQuery?

I'm generating a div dynamically and I've to check whether a dynamically generated div exists or not ? How can I do that?
Currently I'm using the following which does not detects the div generated dynamically. It only detects if there is already an element with the id contained in the HTML template.
$(function() {
var $mydiv = $("#liveGraph_id");
if ($mydiv.length){
alert("HHH");
}
});
How can I detect the dynamically generated div?
If mutation observes aren't an option due to their browser compatibility, you'll have to involve the code that's actually inserting the <div> into the document.
One options is to use a custom event as a pub/sub.
$(document).on('document_change', function () {
if (document.getElementById('liveGraph_id')) {
// do what you need here
}
});
// without a snippet to go on, assuming `.load()` for an example
$('#container').load('/path/to/content', function () {
$(this).trigger('document_change');
});
If it is added dinamically, you have to test again. Let's say, a click event
$("#element").click(function()
{
if($("#liveGraph_id").length)
alert("HHH");
});
How you inserting your dynamic generated div?
It works if you do it in following way:
var div = document.createElement('div');
div.id = 'liveGraph_id';
div.innerHTML = "i'm dynamic";
document.getElementsByTagName('body')[0].appendChild(div);
if ($(div).length > 0) {
alert('exists'); //will give alert
}
if ($('#liveGraph_id').length > 0) {
alert('exists'); //will give alert
}
if ($('#liveGraph_id_extra').length > 0) {
alert('exists'); //wont give alert because it doesn't exist.
}
jsfiddle.
Just for interest, you can also use a live collection for this (they are provided as part of the DOM). You can setup a collection of all divs in the page (this can be done in the head even before the body is loaded):
var allDivs = document.getElementsByTagName('div');
Any div with an id is available as a named property of the collection, so you can do:
if (allDivs.someId) {
// div with someId exists
}
If the ID isn't a valid identifier, or it's held in a variable, use square bracket notation. Some play code:
<button onclick="
alert(!!allDivs.newDiv);
">Check for div</button>
<button onclick="
var div = document.createElement('div');
div.id = 'newDiv';
document.body.appendChild(div);
">Add div</button>
Click the Check for div button and you'll get false. Add the div by clicking the Add div button and check again—you'll get true.
is very simple as that
if(document.getElementById("idname")){
//div exists
}
or
if(!document.getElementById("idname")){
// don't exists
}

How to change text inside span with jQuery, leaving other span contained nodes intact?

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

Categories