I have an HTML table with a time column, whose values I want to change. However, when I do this within the document.ready(), DOM manipulation heavily affects my load time.
Is it possible to change the table column cell values before the DOM loads?
The code I need to use for the manipulation is -
var time_col = rows[i].cells[TimeColumnIndex];
//Calculate new values
var time_Str = getUpdatedValue(time_col.innerText);
//Set values
time_col.innerText = time_Str;
time_col.innerHTML = time_Str;
I would appreciate any suggestions that people have, I'm still trying to understand things related to DOM, so please feel free to tell me if this cannot be done.
EDIT 1:
The getUpdatedValue() function just gets the difference in the users timezone as compared to UTC and adds the required number of minutes.
I've tried commenting out each line to see which lines actually increase the load time, and I found that it was just the DOM manipulation that took time, namely the following lines
time_col.innerText = time_Str;
time_col.innerHTML = time_Str;
My HTML table has about 1500 rows, so I go through each row and change the value of the time column.
If for some reason, you need your code to run immediately after the table has been loaded, you can just place your <script> tag immediately after the closing </table> tag
<table>
<tbody>
<tr><td>A</td><td>B</td></tr>
</tbody>
</table>
<script type="text/javascript">
var tables = document.getElementsByTagName("table");
var tableAbove = tables[tables.length - 1];
</script>
You cannot run code that operates on the DOM before the DOM has loaded. Hopefully, it obvious to you why that would be the case as DOM elements that aren't loaded are not accessible to javascript yet.
The options you have available are as follows:
Locate your script in your page immediately after the part of the DOM that you want to modify. Since things are loaded in pure sequence, you can manipulate any part of the DOM that is physically located before your script in the HTML file.
Use document.ready() for your code and just operate on the table after the whole DOM is loaded.
Hide the table initially with CSS so it is not initally visible. Modify it using either of the above two methods and then when you are done modifying it, show the table. This prevents the table being visible before you've modified it.
If an ajax call is involved in fetching the data for the table, you can further optimize things by starting that ajax call BEFORE the DOM is loaded and just store it's result when it completes (if the DOM isn't yet ready). This parallelizes the two operations so that the ajax call is being fetched at the same time as the DOM is loading. Then, when both the ajax call has completed and the DOM has loaded, you can then insert the ajax result into the DOM.
Related
I have an HTML body, and I want to get its full inner HTML code before its loading is completed.
<body someproperties>
<!--- some elements --->
<script>
var html = getFullInnerHTMLsomeWay();
</script>
<!--- some elements --->
</body>
So, the question is, how can I get its full inner HTML code before all its child are loaded?
I have tried many ideas but no success yet.
I also tried to google it but didn't find anything helpful.
Edit: My goal is to replace all instances of a specified text to another text before they displayed to the user.
The first time elements become interactable with (and, for example, viewable from the DOM APIs and by the user) is when the browser inserts them into the DOM.
Given
<body someproperties>
<!--- some elements 1 --->
<script>
console.log(document.body.innerHTML);
</script>
<!--- some elements 2 --->
</body>
you will get the contents of some elements 1, as well as the script tag, but there's no way to get some elements 2 because it hasn't been loaded yet.
You will only be able to get some elements 2 after the <script> tag finishes executing.
The only way I can think of to do something like this would be to completely stop the page from loading, fetch the current page, then parse the response, and then finally load the response into the current page - which would be quite convoluted, and I wouldn't recommend it at all.
It's not exactly what you were asking, but if desirable, you can alter or view the HTML before it gets displayed - use a MutationObserver to watch for appended nodes on the body.
new MutationObserver(() => {
// examine DOM here
// can add and remove nodes as needed, before they get rendered
})
.observe(document.body, { childList: true });
I have this code that updates the contents of a div every 5 seconds:
<script type="text/javascript">
$(document).ready(function(){
setInterval(sensor,5000);
});
function sensor(){
$("#ex2").load("http://localhost:8050/ss2");
}
</script>
The content is a table that shows the data of a database and it is constantly updated, the information is updated but at the moment these updates start it brings me the whole page inside the div in this way:
Does anyone know how I can solve this problem?
As for what I can see http://localhost:8050/ss2 is also the URL of your page to visit? You should create another page that only gives you the html of the table, then you can replace the original contents.
Or you should extract the table html from the data you have (not sure what it's code is to be able do this for you). Then create a node from that text and add it to you r DOM
I don't consider myself a professional by any means. I decided to spend this summer picking up a few web languages that would allow me to prototype my ideas (I am a designer).
To get with the question, I am having a tough time figuring out how to manipulate elements that I am echoing back from an external .php script. Essentially I am doing this.
process_feed.php:
- Gets data, does SQL search based on data, outputs rows
while ($row = mysql_fetch_assoc($feedResult))
{
$ctime = date("U",strtotime($row['timestamp']));
echo '<div id="secretmsg">'.$row['secretmsg'].'</br>';
echo '<div id="postedby">Posted By: '.$row['postedby'].'</div>';
echo '<div id="timestamp">'.ago($ctime).'</div><button type ="button" name="'.$row['m_id'].'">Reply</button></div>';
}
main page:
function RefreshFeed()
{
var SchoolName = document.getElementById('schoolname').innerHTML;
$.post('../../process_feed.php', {name: SchoolName}, processResponse);
function processResponse(data) {
$('.secretfeed').html(data);
}
}
Perhaps not the best solution, but I have RefreshFeed on an interval so I can constantly get updated information.
The issue is this: I am trying to work on a comment system where users can respond to each post. On my process page, I am adding a Reply button with the name set to the ID in the database. I am trying to setup basic functionality where the Reply button will open up a text input for commenting, send the message to the DB based on the ID, etc etc. However, on my main page I am not able to manipulate the element because it's being echoed? What can I change in order to echo information from the database onto my main page, and then from my main page manipulate the echoed div's.
I hope this makes sense - thanks for the help :)
If I understand you correctly then you would like to modify the DOM once the data has been added - so you can then just use a selector to get the desired element and do what ever you want - e.g.:
function processResponse(data) {
// Selector to get all elements by class name within the whole document
$('.secretfeed').html(data);
// Selector to get all buttons by tag name inside $('.secretfeed')
$('.secretfeed').find('button').text('foo');
// Selector to get all buttons by attribute inside $('.secretfeed')
$('.secretfeed').find('[type="button"]').text('bar');
// Selector to get the element with the given id within the whole document
$('#secretmsg').css('color', '#ff0000');
}
Notes:
Ids for HTML elements should always be unique within the whole document! In your example you possibly echo multiple elements with the same id (as it is inside a while loop) - use class="" instead.
It is recommended to save selectors so that jQuery does not need to parse the DOM over and over again - e.g.:
var $myselector = $('.myclass');
$myselector.text('foo');
But keep in mind that the selector is not updated when you modify the DOM by e.g. adding another element with class="myclass" - you would then need to assign the variable again so the selector contains the newly inserted element as well.
Additionally be sure that the DOM is ready when you want to work on it - regarding your callback processResponse this will always be the case as jQuery takes care of it and does not execute the callback until it is ready - but when you come from a page reload wrap your code like this:
var $myselector = $();
$(document).ready(function(){
$myselector = $('.myclass');
});
Additional info:
Finally (out of the scope of your question) take a look at event delegation so that you do not need to select all elements directly - e.g. if you want to add a click handler to all of your buttons you do not need to register an event handler for each but can create a global one:
$(document).on('click', '.secretfeed button', function(){
alert($(this).attr('name'));
});
First of all I would like to say that while this is the first time i post here these boards have helped me much.
With that said, I have got a strange issue regarding AJAX and scripts.
You see, in my web application i used custome JS context menus. Now each of them menus is implemented with specific features depending on the object and if the object exists.
E.x : if we got an upper menu place holder but no upper menu the context menu will have one option which is "add menu".
But say we already have the upper menu the context menu will have different options such as "edit menu" etc...
so far so good, however, say we have an upper menu place holder and no menu and then we added the menu (still no refresh on the page) i need to generate a new context menu and inject it right? so i do just that along with the new menu i just built.
all that code goes into the SAME div where the old context menu script and upper menu place holder were so basicaly they are overwriten.
Now the menu itself is in HTML so it overrides the current code the JS however acts wierd and will show now 2 context menus the old one and the new one even though i overwrite it's code.
I need to some how get rid of the old context menu script without refreshing the page.
Any ideas?
P.S
all the JS are dynamicaly generated if that makes any difference (i dont think it does.)
Well after some head breaking i figured it out..
(the problem not the solution yet) this is the ajax function right?
$.ajax({
type: "GET",
url: "../../../Tier1/EditZone/Generate.aspx?Item=contentholder&Script=true",
dataType: "html",
success: function (data) {
$('#CPH_Body_1_content_holder').html(data);
}
});
now they function uses a page with an event handler, that event handler reutnrs the data as followed response.write(answer) it just hit me that when you use response.write it sends the code after it's been compiled and ran in our case at page Generate.aspx.
so the script will run but not in the page i intended it to run and because of that i cannot overwrite it... how silly of me.
what i think ill do it return the data as an actualy string and then and only then inject the code into the container div.
ill let you folks know if that works out.
cheers and thanks for the advice these forums rock.
No matter what anyone says, do not use EVAL. It's evil and will give you memory issues if used more than a few times on a page.
See my soluition here: trying to call js code that is passed back from ajax call
Basically, create a div with the ID of "codeHolder" and voila. You'll basically want to pass your HTML and JS back to the AJAX receiver (separated by a separator), parse it on the JS side, display the HTML and put the JS Code in your javascriptCode variable.
//Somehow, get your HTML Code and JS Code into strings
var javascriptCode="function test(){.....}";
var htmlCode="<html>....</html>";
//HTML /////////////////////////////////////////
//Locate our HTML holder Div
var wndw=document.getElementById("display");
//Update visible HTML
wndw.innerHTML = htmlCode;
//Javascript ///////////////////////////////////
//Create a JSON Object to hold the new JS Code
var JSONCode=document.createElement("script");
JSONCode.setAttribute("type","text/javascript");
//Feed the JS Code string to the JSON Object
JSONCode.text=javascriptCode;
//Locate our code holder Div
var cell=document.getElementById("codeHolder");
//Remove all previous JS Code
if ( cell.hasChildNodes() )
while ( cell.childNodes.length >= 1 )
cell.removeChild( cell.firstChild );
//Add our new JS Code
cell.appendChild(JSONCode);
//Test Call///////////////////////////////////////
test();
This code will replace all previous JS code you might have put there with the new JS Code String.
Thanks for the replies.
Dutchie - that's exactly what I did. now the thing is the HTML is properly overwritten (I didn't use append I overwrote the entire div) and yes the javascript just keeps on caching...
I tried to disable browser cache and still the problem persists i get multiple context menu per item the more I ran the ajax function...
Jan,
My AJAX function builds a div tag and script tags and places them into another container div tag in the page.
What's suppose to happen is that every time the AJAX runs the code inside the container div is overwritten and you get an updated version.
the div inside the container div is overwritten yet the script tags somehow are cached into the memory and now each time the out jQuery function calls the context menu i get multiple menus...
I don't think code is needed but I will post it tomorrow.
Any ideas?
im having a firefox issue where i dont see the wood for the trees
using ajax i get html source from a php script
this html code contains a tag and within the tbody some more tr/td's
now i want to append this tbody plaincode to an existing table. but there is one more condition: the table is part of a form and thus contains checkboxe's and drop down's. if i would use table.innerHTML += content; firefox reloads the table and reset's all elements within it which isnt very userfriendly as id like to have
what i have is this
// content equals transport.responseText from ajax request
function appendToTable(content){
var wrapper = document.createElement('table');
wrapper.innerHTML = content;
wrapper.setAttribute('id', 'wrappid');
wrapper.style.display = 'none';
document.body.appendChild(wrapper);
// get the parsed element - well it should be
wrapper = document.getElementById('wrappid');
// the destination table
table = document.getElementById('tableid');
// firebug prints a table element - seems right
console.log(wrapper);
// firebug prints the content ive inserted - seems right
console.log(wrapper.innerHTML);
var i = 0;
// childNodes is iterated 2 times, both are textnode's
// the second one seems to be a simple '\n'
for(i=0;i<wrapper.childNodes.length;i++){
// firebug prints 'undefined' - wth!??
console.log(wrapper.childNodes[i].innerHTML);
// firebug prints a textnode element - <TextNode textContent=" ">
console.log(wrapper.childNodes[i]);
table.appendChild(wrapper.childNodes[i]);
}
// WEIRD: firebug has no problems showing the 'wrappid' table and its contents in the html view - which seems there are the elements i want and not textelements
}
either this is so trivial that i dont see the problem OR
its a corner case and i hope someone here has that much of expirience to give an advice on this - anyone can imagine why i get textnodes and not the finally parsed dom elements i expect?
btw: btw i cant give a full example cause i cant write a smaller non working piece of code
its one of those bugs that occure in the wild and not in my testset
thx all
You are probably running into a Firefox quirk of following the W3C spec. In the spec the whitespace between tags are "text" nodes instead of elements. These TextNodes are returned in childNodes. This other answer describes a workaround. Also Using something like JQuery makes this much easier.
I would expect this behavior in any browser as the += operand overwrites what is already in the table by definition. Two solutions:
Instead of receiving HTML code from your PHP file, have the PHP generate a list of items to add to the table. Comma/tab separated, whatever. Then use Table.addRow(), Row.addCell() and cell.innerHTML to add the items to the table. This is the way I would suggest doing it, no point in creating GUI elements in two separate files.
The other solution is to save all the form data that's already been entered to local JavaScript variables, append the table, and then reload the data into the form fields.
Well, returning a JSON object with the new data seems like the best option. Then, you can synthesize the extra table elements by using it.
In case one is forced to get plain HTML as response, it is possible to use var foo = document.createElement('div');, for example, and then do foo.innerHTML = responseText;. This creates an element that is not appended to anything, yet hosts the parsed HTML response.
Then, you can drill down the foo element, get the elements that you need and append them to the table in a DOM-friendly fashion.
Edit:
Well, I think I see your point now.
wrapper is a table element itself. The nodes reside under the tbody, a child of wrapper which is its lastChild (or you can access it via its tBodies[0] member, in Firefox).
Then, using the tBody element, I think that you would be able to get what you want.
BTW, You do not need to append the wrapper to the document before appending its children to the table, so no need to hide it etc.