I've got a webpage which uses the JQuery ToolTips plugin for popup boxes with extra information. That's all working fine with no issues.
However in order for the popup boxes to work perfectly I need to give the elements in question titles detailing out what I want the popups to say. This would be simple if I could change the HTML directly but I can only do it through JS. More to bother me, the tooltip changes depending on the content of what's in the elements innerHTML, but the element itself doesn't have an ID. It's parent however does have an ID.
so I've been trying to access the child node through the parent, reads it's innerHTML, compare it to a few if statements and then apply a title to the parent based on this innerHTML.
Here is my code:
for(var i = 1; i<5; i++){
var q = document.getElementById("cell.0."+i);
console.log(i+" "+q);
if(q.children[0].innerHtml === "some text1"){
q.setAttribute('title', 'Other text1');
}
else if(q.children[0].innerHtml === "some text2"){
q.setAttribute('title', 'Other text2');
}
else if(q.children[0].innerHtml === "some text3"){
q.setAttribute('title', 'Other text3');
}
else if(q.children[0].innerHtml === "some text4"){
q.setAttribute('title', 'Other text4');
}
}
And an accompanying JSFiddle to make it a bit clearer: http://jsfiddle.net/qxb58/7/
Note: the JSFiddle uses a button, but the actual function I'm using will be on page load.
I've been testing each line in the console. From what I can tell all of the statements which are immediately testable in the console work (e.g. q.children[0].innerHtml === "some text4" and q.setAttribute('title', 'Other text4');). But when put into a for loop it doesn't seem to work.
Note it's unlikely to be a HTML error as my HTML is autogenerated and works. If there is an error with the HTML in the fiddle, it's me being crap at HTML. Thanks for pointing it out though!
EDIT: Solution: innerHTML not innerHtml. Sorry for the stupid mistake. And thanks for the help!
You were executing javascript onload which meant that when the DOM was created with the function changer(), it was undfined at that time. Also you were looking for property innerHtml instead of innerHTML. Properties are case senstive. With these two changes, it works fine:
JSFiddle
Aside from your case problem, you also have the problem of your HTML being invalid. Enclose your <tr>s in a and it works:
http://jsfiddle.net/qxb58/7/
<table>
<tr>
<td id="cell.0.1"> <span>some text1</span>
</td>
</tr>doc
<br/>
<tr>
<td id="cell.0.2"> <span>some text2</span>
</td>
</tr>
<br/>
<tr>
<td id="cell.0.3"> <span>some text3</span>
</td>
</tr>
<br/>
<tr>
<td id="cell.0.4"> <span>some text4</span>
</td>
</tr>
</table>
<br/>
<br/>
<button onClick="changer()">Changing</button>
Still not 100% correct, but working.
Oh, also, you need to set your fiddle to put your script in the head. You had it in the onload which won't work because the handler won't be defined.
Edit: Sorry, missed the part of actually setting the title. Your problem there is that you need innerText not innerHTML. See here: http://jsfiddle.net/qxb58/15/
Finally: if you are using a jQuery plugin for your tooltips, why not use jQuery throughout instead of getElementById
In HTML ids are case sensitive.
You set them in lower case and query them in JS with an upper case C.
Correct it this way:
q = document.getElementById("cell.0."+i);
^ lower case now
This will not solve the problem but is just one of a multi-step debug. Below is a further answer solving the problem.
EDIT: this works now. I corrected the upper case C and replaced innerHtml with innerText.
And BTW, innerHtml is written this way:
innerHTML
^^^^ all upper case
Copy & paste solution:
function changer()
{
for (var i = 1; i < 5; i++)
{
var q = document.getElementById("cell.0." + i);
if (q.children[0].innerText === "some text1") {
q.setAttribute('title', 'Other text1');
} else if (q.children[0].innerText === "some text2") {
q.setAttribute('title', 'Other text2');
} else if (q.children[0].innerText === "some text3") {
q.setAttribute('title', 'Other text3');
} else if (q.children[0].innerText === "some text4") {
q.setAttribute('title', 'Other text4');
}
}
}
Related
In the past I used Google Developer Console to delete some specific divs on a page. I could do it manually of course but in some cases where the divs where many I had to use the console. I had a single line code that did the job (I found it while searching the internet) but I lost my note.
So how can I delete using javascript any html code (by copy pasting the code).
Something like:
elements = $('<div ... </div>');
elements.remove();
OR
$('<div ... </div>').remove();
Any ideas? I am not an expert in javascript (obviously) and I've been searching stackoverflow for hours without finding anything that works.
UPDATE: I think some people might get confused with my question. Google developer console accepts javascript command lines. So even though I ask for javascript I will use the code on the google developer console.
UPDATE 2 :
Here is an example of a div I need to delete. Keep in mind I want to copy paste the entire code in the javascript code. Not just identify the div.
<div class="entry-status-overlay" data-entry-status="declined">
<div class="entry-status-overlay__inner">
<span class="entry-status-overlay__title">Declined</span>
</div>
</div>
It's the data-entry-status="declined" that makes that div unique so I can't just identify the div using an id selector or a class selector. I need to put the entrire thing there and remove it.
I tried:
$('<div class="entry-status-overlay" data-entry-status="declined"><div class="entry-status-overlay__inner"><span class="entry-status-overlay__title">Declined</span></div></div>').remove();
It didn't remove the div.
Try to search the dom by its outerHTML.
function deleteDomByHtml(html){
html=html.replace(/\s/g,'');
$("*").each(function(){
if(this.outerHTML.replace(/\s/g,'')===html){
$(this).remove();
}
});
}
And try this line on this page:
deleteDomByHtml(`<span class="-img _glyph">Stack Overflow</span>`);
You cannot do by simply pasting the code. That will remove all the div element.
You may need a specific selector like id,class or child to specific parent to remove the element from the dom.
Consider this case the divs have common class but the data-entry-status is different. So you can get the dom using a selector and then check the dataset property.
For demo I have put it inside setTimeout to show the difference. In application you can avoid it
setTimeout(function() {
document.querySelectorAll('.entry-status-overlay').forEach(function(item) {
let getStatus = item.dataset.entryStatus;
if (getStatus === 'declined') {
item.remove()
}
})
}, 2000)
<div class="entry-status-overlay" data-entry-status="declined">
<div class="entry-status-overlay__inner">
<span class="entry-status-overlay__title">Declined</span>
</div>
</div>
<div class="entry-status-overlay" data-entry-status="accepted">
<div class="entry-status-overlay__inner">
<span class="entry-status-overlay__title">accepted</span>
</div>
</div>
Just add any attribute with [] and it will remove the element.
$('[class="entry-status-overlay"]').remove();
/*OR*/
$('[data-entry-status="declined"]').remove();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="entry-status-overlay" data-entry-status="declined">
<div class="entry-status-overlay__inner">
<span class="entry-status-overlay__title">Declined</span>
</div>
</div>
function del(){
var h = document.body.outerHTML;
h = h.match('<div>...</div>');
h.length--;
return h;
}
I guess this will work just give it a try... i tried on browser console and it worked, this way you can match the exact you want.
I might as well add my take on this. Try running this in your console and see the question vanish.
// convert the whole page into string
let thePage = document.body.innerHTML,
string = [].map.call( thePage, function(node){
return node.textContent || node.innerText || "";
}).join("");
// I get some string. in this scenario the Question or you can set one yourself
let replacableCode = document.getElementsByClassName('post-layout')[0].innerHTML,
string2 = [].map.call( replacableCode, function(node){
return node.textContent || node.innerText || "";
}).join("");
// replace whole page with the removed innerHTML string with blank
document.body.innerHTML = thePage.replace(replacableCode,'');
If you want to identify divs with that particular data attribute, you can use a data-attribute selector. In the example below, I've used a button and click event to make the demo more visual, but in the console the only line you'd need would be:
$('div[data-entry-status="declined"]').remove();
$(function() {
$("#testbutton").click(function() {
$('div[data-entry-status="declined"]').remove();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="entry-status-overlay" data-entry-status="declined">
<div class="entry-status-overlay__inner">
<span class="entry-status-overlay__title">Declined</span>
</div>
</div>
<div id="x">Some other div</div>
<button type="button" id="testbutton">Click me to test removing the div</button>
See https://api.jquery.com/category/selectors/attribute-selectors/ for documentation of attribute selectors.
P.S. Your idea to paste some raw HTML into the jQuery constructor and then execute "remove" on it cannot work - you're telling jQuery to create an object based on a HTML string, which is, as far as it's concerned, a new set of HTML. It does not try to match that to something existing on the page, even if that exact HTML is in the DOM somewhere, it pays it no attention. It treats what you just gave it as being totally independent. So then when you run .remove() on that new HTML...that HTML was never added to the page, so it cannot be removed. Therefore .remove() has no effect in that situation.
text replace "false" to "true"
ori from html (dont change) :
<td align="center">false</td>
to
<td align="center">true</td>
my js code error :
document.body.innerHTML = document.body.innerHTML.replace(/<td align=\"center\">false<\/td>/g,"<td align=\"center\">true<\/td>");
http://jsfiddle.net/PKM6U/
Since you are new to this I would recommend you use a framework/library to make thing easier for you
jQuery have a nice selector that will help you with this
http://jquery.com/
http://jquery.com/download/
http://api.jquery.com/contains-selector/
This code will do what you want
function swapTrueFalse(){
if($("td[align=center]:contains('true')"){
$("td[align=center]:contains('true')").text('false')
}else if($("td[align=center]:contains('false')"){
$("td[align=center]:contains('false')").text('true')
}
}
I would suggest you add a class to the element however as this will make it more efficient:
<td align="center" class='true-false'>true</td>
Change the code to match:
function swapTrueFalse(){
var t = $(".true-false").text()
if(t === "true"){
$(".true-false").text("false");
}else{
$(".true-false").text("true");
}
}
Using regex to parse HTML in the way you are is extremely inefficient so I do advise against it.
<td align="center" id="changeme">false</td>
in js
document.getElementById("changeme").text="true"
Works just fine if you replace your all "td" with "span". Having td nodes by themselves doesn't really make sense and it appears as though they disappear completely after the fiddle is ran.
I have a problem with replacing html elements.
For example, here is a table:
<table>
<tr>
<td id="idTABLE">0</td>
<td>END</td>
</tr>
</table>
(it can be div, span, anything)
And string in JavaScript:
var str = '<td>1</td><td>2</td>';
(It can be anything, 123 text, <span>123 element</span> 456 or <tr><td>123</td> or anything)
How can I replace element idTABLE with str?
So:
<table>
<tr>
<td id="idTABLE">0</td>
<td>END</td>
</tr>
</table>
Becomes:
<table>
<tr>
<td>1</td>
<td>2</td>
<td>END</td>
</tr>
</table>
<!-- str = '<td>1</td><td>2</td>'; -->
<table>
<tr>
123 text
<td>END</td>
</tr>
</table>
<!-- str = '123 text' -->
<table>
<tr>
<td>123</td>
<td>END</td>
</tr>
</table>
<!-- str = '<td>123</td>' -->
I tried createElement, replaceChild, cloneNode, but with no result at all =(
As the Jquery replaceWith() code was too bulky, tricky and complicated, here's my own solution. =)
The best way is to use outerHTML property, but it is not crossbrowsered yet, so I did some trick, weird enough, but simple.
Here is the code
var str = 'item to replace'; //it can be anything
var Obj = document.getElementById('TargetObject'); //any element to be fully replaced
if(Obj.outerHTML) { //if outerHTML is supported
Obj.outerHTML=str; ///it's simple replacement of whole element with contents of str var
}
else { //if outerHTML is not supported, there is a weird but crossbrowsered trick
var tmpObj=document.createElement("div");
tmpObj.innerHTML='<!--THIS DATA SHOULD BE REPLACED-->';
ObjParent=Obj.parentNode; //Okey, element should be parented
ObjParent.replaceChild(tmpObj,Obj); //here we placing our temporary data instead of our target, so we can find it then and replace it into whatever we want to replace to
ObjParent.innerHTML=ObjParent.innerHTML.replace('<div><!--THIS DATA SHOULD BE REPLACED--></div>',str);
}
That's all
Because you are talking about your replacement being anything, and also replacing in the middle of an element's children, it becomes more tricky than just inserting a singular element, or directly removing and appending:
function replaceTargetWith( targetID, html ){
/// find our target
var i, tmp, elm, last, target = document.getElementById(targetID);
/// create a temporary div or tr (to support tds)
tmp = document.createElement(html.indexOf('<td')!=-1?'tr':'div'));
/// fill that div with our html, this generates our children
tmp.innerHTML = html;
/// step through the temporary div's children and insertBefore our target
i = tmp.childNodes.length;
/// the insertBefore method was more complicated than I first thought so I
/// have improved it. Have to be careful when dealing with child lists as
/// they are counted as live lists and so will update as and when you make
/// changes. This is why it is best to work backwards when moving children
/// around, and why I'm assigning the elements I'm working with to `elm`
/// and `last`
last = target;
while(i--){
target.parentNode.insertBefore((elm = tmp.childNodes[i]), last);
last = elm;
}
/// remove the target.
target.parentNode.removeChild(target);
}
example usage:
replaceTargetWith( 'idTABLE', 'I <b>can</b> be <div>anything</div>' );
demo:
http://jsfiddle.net/97H5Y/1/
By using the .innerHTML of our temporary div this will generate the TextNodes and Elements we need to insert without any hard work. But rather than insert the temporary div itself -- this would give us mark up that we don't want -- we can just scan and insert it's children.
...either that or look to using jQuery and it's replaceWith method.
jQuery('#idTABLE').replaceWith('<blink>Why this tag??</blink>');
update 2012/11/15
As a response to EL 2002's comment above:
It not always possible. For example, when createElement('div') and set its innerHTML as <td>123</td>, this div becomes <div>123</div> (js throws away inappropriate td tag)
The above problem obviously negates my solution as well - I have updated my code above accordingly (at least for the td issue). However for certain HTML this will occur no matter what you do. All user agents interpret HTML via their own parsing rules, but nearly all of them will attempt to auto-correct bad HTML. The only way to achieve exactly what you are talking about (in some of your examples) is to take the HTML out of the DOM entirely, and manipulate it as a string. This will be the only way to achieve a markup string with the following (jQuery will not get around this issue either):
<table><tr>123 text<td>END</td></tr></table>
If you then take this string an inject it into the DOM, depending on the browser you will get the following:
123 text<table><tr><td>END</td></tr></table>
<table><tr><td>END</td></tr></table>
The only question that remains is why you would want to achieve broken HTML in the first place? :)
Using jQuery you can do this:
var str = '<td>1</td><td>2</td>';
$('#__TABLE__').replaceWith(str);
http://jsfiddle.net/hZBeW/4/
Or in pure javascript:
var str = '<td>1</td><td>2</td>';
var tdElement = document.getElementById('__TABLE__');
var trElement = tdElement.parentNode;
trElement.removeChild(tdElement);
trElement.innerHTML = str + trElement.innerHTML;
http://jsfiddle.net/hZBeW/1/
You would first remove the table, then add the new replacement to the table's parent object.
Look up removeChild and appendChild
http://javascript.about.com/library/bldom09.htm
https://developer.mozilla.org/en-US/docs/DOM/Node.appendChild
Edit:
jQuery .append allows sting-html without removing tags: http://api.jquery.com/append/
Your input in this case is too ambiguous. Your code will have to know if it should just insert the text as-is or parse out some HTML tags (or otherwise wind up with bad HTML). This is unneeded complexity that you can avoid by adjusting the input you provide.
If the garbled input is unavoidable, then without some sophisticated parsing (preferably in a separate function), you could end up with some bad HTML (like you do in your second example... which is Bad, right?).
I'm guessing you want a function to insert columns into a 1-row table. In this case, your contents should be passed in as an array (without table, tr, td tags). Each array element will be one column.
HTML
<table id="__TABLE__"><tr><td></td></tr></table>
JS
using jQuery for brevity...
function insert_columns (columns)
{
var $row = $('<tr></tr>');
for (var i = 0; i < columns.length; i++)
$row.append('<td>'+columns[i]+'</td>');
$('#__TABLE__').empty(); // remove everything inside
$('#__TABLE__').append($row);
}
So then...
insert_columns(['hello', 'there', 'world']);
Result
<table id="__TABLE__"><tr><td>hello</td><td>there</td><td>world</td></tr></table>
If you need to actually replace the td you are selecting from the DOM, then you need to first go to the parentNode, then replace the contents replace the innerHTML with a new html string representing what you want. The trick is converting the first-table-cell to a string so you can then use it in a string replace method.
I added a fiddle example: http://jsfiddle.net/vzUF4/
<table><tr><td id="first-table-cell">0</td><td>END</td></tr></table>
<script>
var firstTableCell = document.getElementById('first-table-cell');
var tableRow = firstTableCell.parentNode;
// Create a separate node used to convert node into string.
var renderingNode = document.createElement('tr');
renderingNode.appendChild(firstTableCell.cloneNode(true));
// Do a simple string replace on the html
var stringVersionOfFirstTableCell = renderingNode.innerHTML;
tableRow.innerHTML = tableRow.innerHTML.replace(stringVersionOfFirstTableCell,
'<td>0</td><td>1</td>');
</script>
A lot of the complexity here is that you are mixing DOM methods with string methods.
If DOM methods work for your application, it would be much bette to use those.
You can also do this with pure DOM methods (document.createElement, removeChild, appendChild), but it takes more lines of code and your question explicitly said you wanted to use a string.
use the attribute "innerHTML"
somehow select the table:
var a = document.getElementById('table, div, whatever node, id')
a.innerHTML = your_text
I have a table:
<table>
<tr>
<td colspan="2"><h2>Order Awards here:</h2></td>
</tr>
<tr>
<td class="aocBlack">Delivery:</td>
<td>
<select style="width: 200px;" id="deliveryMethod" name="deliveryMethod" size="1" onchange="showMailing()">
<option value="print">I will print it myself.</option>
<option value="mail">Please mail it to me.</option></select>
</td>
</tr>
<tr id="messageText" style="">
<td class="aocBlack" colspan="2">Message to appear on card:</td>
</tr>
<tr id="messageText2" style="">
<td colspan="2"><textarea id="certMessage" name="certMessage" rows="5" cols="10" style="width: 284px;"></textarea></td>
</tr>
</table>
When the select box called deliveryMethod is set to "print", the following two table rows (id messageText and messageText2) should be visible. When it's set to "mail", they should be hidden. I have some javascript that's worked before with no problem, but the id's I was targeting before were always divs. I don't know if table rows behave differently, but I'm getting some strange results. Here's the JS:
function showMailing(){
e = document.getElementById("deliveryMethod");
eVal = e.options[e.selectedIndex].value;
if (eVal == "mail"){
document.getElementById("messageText").style.display="none";
document.getElementById("messageText2").style.display="none";
}else{
document.getElementById("messageText").style.display="inline";
document.getElementById("messageText2").style.display="inline";
}
}
The results are somewhat strange, to my (admittedly javascript/css-rusty) eyes. For example, when the page initially loads, everything displays as it's supposed to: the dropdown's default value is "print", and so the two table rows in question display. When you change the dropdown to "mail", they both disappear. But when you change it back, the fields are all pushed over out of where they're supposed to be. These results are consistent across FF and Chrome (strangely it works correctly in IE) so I have to assume I'm doing something wrong, but I don't know what.
Here are some screenshots (note there are a few fields displayed in the screenshot that I've stripped out of the code shown here just for clarity.) Can anyone help me out here?
On initial load:
After changing from print to mail:
After changing back from mail to print:
The default display value for a table row is table-row(*). If you set it to inline instead you'll be asking the browser to draw table cells inside inline text instead of a row, which will confuse it and give unspecified results.
(*: except on IE<8, which don't support the table-related display values, instead setting them all to block and giving the elements themselves magic layout powers.)
The better way do show/hide, where you don't have to worry about what the default display value might be, is to define a class:
.hidden { display: none; }
and then toggle that class on and off the element.
document.getElementById('deliveryMethod').onchange= function() {
var cls= this.value==='mail'? 'hidden' : '';
document.getElementById('messageText').className= cls;
document.getElementById('messageText2').className= cls;
};
Assigning the handler from script allows you to drop the onchange inline attribute. You also don't need size="1" (that goes without saying for a single-select), or the style="".
The business with reading the select's value using this.options[this.selectedIndex].value you probably don't need any more, unless you're dealing with ancient browsers.
function showMailing(){
e = document.getElementById("deliveryMethod");
eVal = e.options[e.selectedIndex].value;
if (eVal == "mail"){
document.getElementById("messageText").style.display="none";
document.getElementById("messageText2").style.display="none";
}else{
document.getElementById("messageText").style.display="table-row";
document.getElementById("messageText2").style.display="table-row";
}
}
I'd recommend avoiding "eVal" as a variable name, because there's a native JS method called eval(). The capitalization you used is different ("eVal" not "eval"), so it probably won't break things. But it could easily be confusing to a human reader. Also, if you accidentally forget to capitalize the "V" and then need to use the eval() method, it could break your script.
So just in general, avoid using variable names that are similar to the names of existing methods. May I suggest "selectedOption" or "sel" or something?
I have the following function:
<script type="text/javascript">
function changeText(elem){
var oldHTML = document.getElementById(elem).innerHTML;
var newHTML = "<span style='color:red'>" + oldHTML + "</span>";
document.getElementById(elem).innerHTML = newHTML;
}
</script>
And the following HTML:
<table>
<tr>
<td id = "foo">bar</td>
</tr>
</table>
This throws a "unknown runtime error" (just in IE) which googling has since taught me that table elements are read-only in IE with innerHTML.
I've tried finding workarounds but they don't target my specific problem, which is just that I want to make the word "bar" red. I don't want to change the word "bar" to something else. Purely a color change.
Is there any way to do this without a complex and slow DOM function and without having to change any of the other HTML markup on the page? This is a table with a form in it, and if the surfer submits the form with an error, the "errored" fields should turn red. It has to be able to execute multiple times because it's possible for a surfer to mess up more than one field.
Thanks for any advice.
Why not just change the cell to have color:'red' :
var td = document.getElementById(elem);
td.style.color = 'red';
Couple ways to go about it. Here are some quick ones to get you going -- or until someone else comes with a cleaner/better method.
I prefer the following: define an error class in css:
.errorHighlight { color:red;}
Then for the javascript:
function changeText(elem){
document.getElementById(elem).className="errorHighlight";
}
function changeTextBack(elem){
document.getElementById(elem).className="";
}
This assumes that you don't have any classes set already. If you do you may need to read the name, and append the error class with a space.
Again, there are a lot of ways to approach this and you want to pick the one best suited for your application.