innerHTML manipulation in JavaScript - javascript

I am developing a web page code, which fetches dynamically the content from the server and then places this content to container nodes using something like
container.innerHTML = content;
Sometimes I have to overwrite some previous content in this node. This works fine, until it happens that previous content occupied more vertical space then a new one would occupy AND a user scrolled the page down -- scrolled more than new content would allow, provided its height.
In this case the page redraws incorrectly -- some artifacts of the old content remain. It works fine, and it is even possible to get rid of artifacts, by minimizing and restoring the browser (or force the window to be redrawn in an other way), however this does not seem very convenient.
I am testing this only under Safari (this is a iPhone-optimized website).
Does anybody have the idea how to deal with this?

The easiest solution that I have found would be to place an anchor tag <a> at the top of the div you are editing:
<a name="ajax-div"></a>
Then when you change the content of the div, you can do this to have the browser jump to your anchor tag:
location.hash = 'ajax-div';
Use this to make sure the user isn't scrolled down too far when you update the content and you shouldn't get the issue in the first place.
(tested in the latest FF beta and latest safari)

It sounds like the webkit rendering engine of Safari is not at first recognizing the content change, at least not fully enough to remove the previous html content. Minimizing and then restoring the windows initiates a redraw event in the browser's rendering engine.
I think I would explore 2 avenues: first could I use an iframe instead of the current 'content' node? Browsers expect IFrames to change, however as you're seeing they're not always so good at changing content of DIV or other elements.
Secondly, perhaps by modifying the scroll position as suggested earlier. You could simply move the scroll back to 0 as suggested or if that is to obtrusive you could try to restore the scroll after the content change. Subtract the height of the old content node from the current scroll position (reseting the browser's scroll to the content node's 0), change the node content, then add the new node's height to the scroll position.
Palehorse is right though (I can't vote his answer up at the moment - no points) an abstraction library like jQuery, Dojo, or even Prototype can often help with these matters. Especially if you see your page / site moving beyond simple DOM manipulation you'll find the tools and enhancements provided by libraries to be a huge help.

It sounds like you are having a problem with the browser itself. Does this problem only occur in one browser?
One thing you might try is using a lightweight library like jQuery. It handles browser differences fairly nicely. To set the inner HTML for a div with the ID of container you would simply write this:
$('#container').html( content );
That will work in most browsers. I do not know if it will fix your problem specifically or not but it may be worth a try.

Would it work to set the scroll position back to the top (element.scrollTop = 0; element.scrollLeft = 0; by heart) before replacing the content?

Set the element's CSS height to 'auto' every time you update innerHTML.

I would try doing container.innerHTML = ''; container.innerHTML = content;

Related

How can I force an iframe to resize to fit the embedded document?

I have an iframe that has quite a bit of white space tacked onto the end of visible elements. In fact, I know that the iframe is loading the size of all my elements including hidden elements. These elements were meant to be hidden until some knockout questions are answered, at which point the iframe should resize accordingly.
The other battle I am fighting with this is the fact that I am also having to deal with two scroll bars, one for the iframe, and of course the web page scroll bar. This is just very tacky and not very user friendly.
This is a problem I inherited, so I am hoping for a solution involving the iframe. I am also willing to explore other solutions as maybe this is not the most appropriate as it is.
To get rid of scroll bars, try adding scrolling="no" to the iframe.
HTML iframe - disable scroll
You might update the height of the <iframe> from the framed page using JavaScript after a new element is shown.
function resizeParent() {
if (!window.parent) return;
var height = $(document).height();
$(window.parent.document).find('iframe').height(height);
}
Demo
Source of framed page
Note, this will only work if both pages are loaded from the same domain.
Use both the inline style attribute style="overflow:hidden;" as well as the attribute scrolling="no". overflow:hidden is the proper HTML5 counterpart, so it's best to mix both.
Edit: In fact, if it is suited for your case, try using the iframe seamless boolean attribute. It practically makes the iframe styled as if it's part of the containing document, including no borders or scrollbars. I recommend it because it's like a one-stop for what you need to accomplish, and it does the work for you. You can try a combination of all the three attributes I recommended for ideal browser compatibility.

Will the element be visible If it is added to DOM and instantly removed?

Will the element be visible even for a blink of an eye If it is added to DOM and instantly removed?
var feed = $('<div class="entry"></div>').text(data.status).appendTo(app.twitter_feed);
console.log(feed.height());
feed.remove();
I've tried the above code on a few browsers and couldn't see the element. But is this behaviour consistent through all platforms/browsers?
After reading your previous question as well, it seems that you very badly want to calculate the display height of an element before actually displaying it. I 'm not entirely clear why you want to do this (it gives off a bad smell), but here's how to anyway.
Put a <div> in your page with height: 0, overflow: hidden, and the desired width of your element¹. Add the <div> we 're talking about inside that outer helper div (it will not show no matter what), and get its height after the browser performs layout. After that you can proceed however you want (e.g. by moving the inner <div> to another position in the DOM tree).
¹ it would be best to put it exactly where you want the .entry to end up (i.e. the .entry and the helper div will end up being siblings).
PS: It's always better for everyone if you mention your real purpose.
I can imagine a situation wherein for the browser to be able to compute the element's effective height, it will have to render it on the window, or at least have the element's box reflow against the current site layout. It might not be visible (as, yeah, it's instantly removed), but a situation like this will reflow the page, and the movement of the affected elements on the page can be seen.
Images come to mind, for example, because browsers generally have no idea what the dimensions of images are until they try to lay them out (correct me if I'm wrong there though).
So, no, I wouldn't say that this is consistent behavior.
Implement it like this. Make a clone of app.twitter_feed, and send it to hell (Coordinates: x:-30000, y:-30000) and try whatever you like there.
var cloneTWFeed = $(app.twitter_feed).clone();
cloneTWFeed.css("position", "absolute").css("top","-30000").css("left","-30000");
var feed = $('<div class="entry"></div>').text(data.status).appendTo(cloneTWFeed);
console.log(feed.height());
feed.remove();
You current code works just fine, but you never get to see the element, since just after you append it, you remove it.
The browser sees it, by the time that he takes to remove it, just after being appended.
See this working Fiddle Example!
There I've replaced the console.log with an alert() to force the browser to wait for my response, thus enabling me to see the element on the page.
Note: Also works fine with console.log(), given me the 18px of height.
You either have the remove() wrapped on a timer to actually see the element (visually), or if the HTML markup is to intense, or the desired effect is to only collect data from the element, place your element inside an hidden one, that way you can remove it whenever you've done collecting data from it.
If what you must acheive is an height measurement, try to add the element without visibility (see CSS:
http://reference.sitepoint.com/css/visibility)
In a zone of the page that causes no problems on the element flow.

How is this layout issue commonly addressed?

I have a page where the following occurs:
some stuff is rendered. static content, and content meant to be enhanced with javascript.
some of the divs are instrumented for enhancement via jquery in $()
some of these 3rd party scripts measure the divs they are putting content into so they know how to render it.
in the meantime, as other divs are enhanced, sometimes the page gets long enough that a scroll bar appears. that means the page just got thinner and the measurements that the plugins made are now incorrect.
some divs get enhanced with the wrong width.
ugliness!
If I resize the browser, everything "snaps" into place where it should be.
I can see 2 solutions which I don't like.
somehow force the browser to re-layout everything after every enhancement.
force a vertical scrollbar. http://ryanfait.com/resources/forcing-vertical-scrollbars/
This has to be a fairly common issue. Are there other tricks or suggestions?
KISS method : force the vertical scrollbar to be there.
Forgot to mention, you can also simply use this :
html {overflow-y: scroll;}
You could force the scrollbar to always appear in CSS, or you could set your jQuery code to execute when the page has fully loaded instead of when the DOM is ready, example below:
$(window).bind("load", function() {
// code here
});
This may result in 'jerkiness' as content gets rendered, then is shuffled around as the script configures it for the viewport size.
Personally, I'd just force the scrollbar. Most visitors wouldn't even notice it was there all the time anyway.

Hiding and showing div during page scroll on iphone

Need to display an element (div) ontop of webpage. During scroll the element should disappear and reappear after scroll ends.
To add to the complexity:
our code is a guest code (thus we cannot manipulate DOM structure etc).
our code is intended to work on iPhone/iPad (mobile Safari browser)
We've tried to listen to touchstart event on document / body and hide the element (div) in our dedicated handler. However, in some sites, (when DOM structure becomes reasonably complex) the scroll response time increases significantly, even if handler implementation is entirely empty.
We are looking for the proper way to manage the element (re)appearance with a minimal affect of the user experience while scrolling.
I would think Javascript is your best solution. You can dynamically insert your DIV to any content using document.createElement, then also add some javascript to listen for onScroll...
You could even populate the DIV using custom HTML built from the native code if you want.
Any help?
I don't know if you are a jQuery user, but this .scroll() function may help you do exactly what you want to do. Check out the demo to see how it works.
http://api.jquery.com/scroll/
In recent iOS version (5.x) fixed positioning (position:fixed in CSS) is fluently supported, so that your element will be positioned on screen coordinates. That might be a good starting point for solving your troubles.

Problem moving whole html-page down! margin-top to html element doesn't work on all pages

i have a strange css, JS problem. My chrome-extension should move the hole website some pixels down, so i can display a toolbar on top of it.
This works for most pages, but doesn't work for a few. And i can't find out what's the problem. The code for moving the page down is really simple. Just this line, which adds a margin-top to the html-element:
document.getElementsByTagName('html')[0].style.marginTop = '36px !important';
It's easiest explained and seen if you install the addon and browse to www(dot)interspar(dot)at (here it works) and to www(dot)weinwelt(dot)at (here it doesn't work). The addon is found here https://chrome.google.com/webstore/detail/pilobbegphefikcgjpajnneiiahhejam
Please don't consider this as spam, as this addon is only useful for german speaking people and i think there aren't many around here ;)
It doesn't work on that site because its whole content is positioned absolutely (look at <div class="parent">). You need to loop through the whole DOM looking for absolutely positioned elements that have top property and increase its value accordingly as well.
That's only a tip of the iceberg though, as some sites would be adding absolutely positioned elements to the page dynamically, so you would need to listen to dom changes (DOMSubtreeModified event) as well and do all repositioning again.
Try it on the BODY instead;
document.getElementsByTagName('body')[0].style.marginTop = '36px !important';
HTML tag can't have a margin on it.
According to following link "!important" is only supported by safari.
http://hungred.com/how-to/jquery-javascript-css-important/

Categories