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?
Related
This context of this issue is it is a set of measurements needed for review by the user. I'm reviewing some of my code and changing it to bootstrap's classes. I have a php function - reviewSlide(); that prints out the necessary html. From there it calls javascript script - reviewGetMeasurement(); function to grab the measurements the user inputs.
The event that triggers the javascript function is -
<button onclick="slideforms_step17(event);reviewGetMeasurement();" class="mdk_slidesforms_btn"><?= (!empty($button_text)) ? $button_text : 'Next' ?></button>
The function runs then moves into the below function reviewSlide() however if I do have the following code everything runs perfectly and the measurements are gathered and printed to the page.
function reviewSlide() {
<table>
<tr width="33%">
<table class="pktsq_measurement_table_my_account_table">
<tr>
<td colspan="2" class="pktsq_measurement_table_my_account_td pktsq_measurement_table_my_account_td_title">
Personal
</td>
</tr>
<tr>
<td class="pktsq_measurement_table_my_account_td">
Height
</td>
<td class="pktsq_measurement_table_my_account_td pktsq_measurement_table_my_account_td_measurement" id="userHeight"></td>
</tr>
</table>
</tr>
</table>
...
}
If I remove the above table nothing works.
I have tried
function reviewSlide() {
<p id="userHeight"></p>
<p id="userWeight"></p>
...
}
at the top of my function (which is at this stage above the table) and nothing comes up.
I've looked at other people's issues, some of the main problems were the page wasn't loading and you would have to wait for the page to load as the javascript would not see any html. But I believe I have a bit of a quirky problem here regarding the table code
Any help would be grateful. Thank you.
UPDATE and CLARIFICATION (same as comments):
I didn't write this so bear with me but yes reviewSlide is in php. To clarify I have a function stepxx() in a shortcodes.php file. Each step represents a slide and reviewSlide() also represents another slide, in this case the review slide with all the measurements. All this is written in html/php. In stepxx() there is a button tag that calls a javascript function slideforms_stepxx(event);. When each step is complete 1-xx, slidesforms_stepxx(event) is called to check the input.
This is where we come to the review slide. On the slide before the review slide we go into slideforms_step17 check the input and submit the values to the server via jquery. Then we enter the reviewGetMeasurement() function as seen above by <button onclick="slideforms_step17();reviewGetMeasurement();....>. ReviewGetmeasurement's task is to print out the values and this is where my problem lies.
Inside reviewGetMeasurements(), if I print out the value for a variable let's say the height via console.log(height), it'll work and I can see the value in the console. But once if I try to print the value our by doing
document.getElementById("userHeight").innerHTML = height + "cm";
I get null. But I know there is a value height and it's not null. HOWEVER if I put the <table> code from above it will work and the values are printed out. If I use the <p> tags with the right id it won't work.
You can't just blindly put HTML inside of a Javascript or PHP function. What's in those functions must be the appropriate type of code, not HTML.
If it's Javascript, then using Javascript you can create DOM elements and then insert them into the page.
If it's PHP running at page render time on the server, then you can use PHP's echo to insert content into the page.
If it's PHP running in an Ajax call, then you can also use echo to construct a response to the Ajax call.
Here's an example of inserting content into the page from a user event using a Javascript function:
function insertContent(html) {
var div = document.createElement("div");
div.innerHTML = html;
document.body.appendChild(div);
}
document.getElementById("run").addEventListener("click", function() {
insertContent(document.getElementById("newContent").value);
});
<input id="newContent" value="Some Text"> <button id="run">Insert</button>
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');
}
}
}
so i'm calling a function in jquery that's looping over a table and determining whether to hide a row based on a hidden form element within each row.
when i run this script, toggling the rows either way, the browser hangs for at least 5 seconds even though there are fewer than 100 rows.
the js looks like this:
$('input.vv').each(function(index) {
var chk = $(this).val();
if (chk == "0") $(this).parents("tr").slideToggle(function() {
tableRows();
});
});
and a sample row from the html looks like this:
<tr class="sortable part item" id="row803">
<td class="col-check">Interior Fixed Dome Camera Surface Mounted<br />(Panasonic Part No. WV-CW484AS/29)
<input type="hidden" class="vv" value="50" id="v803" /></td>
<td class="col-equip cen" id="q803">70</td>
<td class="col-equip cen" id="s803">50</td>
<td class="col-equip cen"><div id="bom803|092311-001|15" />50</div></td>
<td class="col-equip cen" id="b803"><span class="shipped">20</span></td>
</tr>
the line of jquery.js that firebug refers to is 8449
return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed;
i'm stuck (can't link to the live site sorry). firebug may give me a way out of this but i'm unsure how to use it well enough. thoughts anyone? thanks!
$('input.vv') creates a loop which goes through all input elements, and checks whether they're a part of the vv class.
.parents("tr") loops through all parent nodes, and selects only the <tr> elements.
Then, you call .slideToggle, which creates an effect which requires a significant amount of computing power (at small intervals, CSS style adjustments through JQuery, CSS style parsing by browser). likely to be the main cause
Finally, you're calling tableRows();, which you haven't defined yet.
These operations, on "fewer than 100 rows" requires much computing power.
Try being a little more specific:
$('input.vv').each(function(index) {
if ($(this).value == "0") $(this).parent().parent().slideToggle(function() {
tableRows();
});
});
I have a function that gets raw HTML to output to a table, but I want to take out the first three columns and put them in another div.
I am considering making a div on the page that is hidden, setting this div's html to the raw HTML I get, and then using the selector syntax to strip it into each table's div. Is there a way to do this without the intermediate faux-div to hold the raw HTML?
It all depends out what the "function that gets raw HTML" does. Where is it getting the HTML? If it's in some kind of format other than a rendered node, then you should be able to manipulate it as needed prior to rendering it. If you've got it in a string format (and the markup is valid) jQuery is really good at turning strings into traversible objects. For example:
var xml = '<div><span>hello</span></div>';
console.log($(xml).find('span'));
In FireBug, this displays the span as an object node.
I'm not sure exactly why you'd want to do this, rather than arrange your data server-side, but one approach that works is:
$(document).ready(
function(){
$('table').click(
function(){
$('<table />').appendTo('#newTable').addClass('new');
$('table').eq(0).find('tr td:first-child').each(
function(){
$(this).appendTo('.new').wrap('<tr></tr>');
});
});
});
With the (x)html:
<table>
<tr>
<td>1:1</td>
<td>1:2</td>
<td>1:3</td>
</tr>
<tr>
<td>2:1</td>
<td>2:2</td>
<td>2:3</td>
</tr>
<tr>
<td>3:1</td>
<td>3:2</td>
<td>3:3</td>
</tr>
<tr>
<td>4:1</td>
<td>4:2</td>
<td>4:3</td>
</tr>
</table>
<div id="newTable"></div>
JS Fiddle demo
The demo uses jQuery's click() event, but that's just to show it working interactively; it could certainly be placed straight into the DOM-ready/$(document).ready(function(){/* ... */}); event.
The above code would allow repeated clicks (each time moving the first 'column' into a new table), the edit removes that possibility using jQuery's one(), giving the following jQuery:
$(document).ready(
function(){
$('table').one('click',
function(){
$('<table />').appendTo('#newTable').addClass('new');
$('table').eq(0).find('tr td:first-child').each(
function(){
$(this).appendTo('.new').wrap('<tr></tr>');
});
});
});
JS Fiddle demo, featuring one().
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.