How Can I Prevent Memory Leaks in IE Mobile? - memory

I've written an application for use offline (with Google Gears) on devices using IE Mobile. The devices are experiencing memory leaks at such a rate that the device becomes unusable over time.
The problem page fetches entries from the local Gears database and renders a table of each entry with a link in the last column of each row to open the entry ( the link is just onclick="open('myID')" ). When they've done with the entry they return to the table, which is RE-rendered. It's the repeated building of this table that appears to be the problem. Mainly the onclick events.
The table is generated in essence like this:
var tmp="";
for (var i=0; i<100; i++){
tmp+="<tr><td>row "+i+"</td><td><a href=\"#\" id=\"LINK-"+i+"\""+
" onclick=\"afunction();return false;\">link</a></td></tr>";
}
document.getElementById('view').innerHTML = "<table>"+tmp+"</table>";
I've read up on common causes of memory leaks and tried setting the onclick event for each link to "null" before re-rendering the table but it still seems to leak.
Anybody got any ideas?
In case it matters, the function being called from each link looks like this:
function afunction(){
document.getElementById('view').style.display="none";
}
Would that constitute a circular reference in any way?
Jake

I don't know if it will help with memory, but instead of concatenating your strings, you can push them onto an array and join them for better performance. Something like:
var tmp=[];
for (var i=0; i<100; i++){
tmp.push("<tr><td>row "+i+"</td><td><a href=\"#\" id=\"LINK-"+i+"\""+
" onclick=\"afunction();return false;\">link</a></td></tr>");
}
document.getElementById('view').innerHTML = "<table>"+tmp.join('')+"</table>";

If you are doing a lot of scripting that changes the content of the page there is an IE memory leak that was mentioned in an old AJAX book I have used in the past (and it may well be hitting your here). When a page unload, you need to clear any divs/spans/etc that you have changed, or their contents will remain in memory. Try something like
<script type="text/javascript">
window.onunload = clearAJAXContent;
function clearAJAXContent() {
/* clear any dynamic content placeholders here*/
}
</script>
I believe, when clearing, you want to set the innerHTML to "". When I get home next I'll try to find the book and update my answer if there's anything different, but that should give you something to test in the meantime

Related

How to query for an element inside a dom-repeat

I have been scouring the web for a clear answer on how to query for an element generated by a dom-repeat element from Dart code.
sample.html
<dom-module id="so-sample>
<style>...</style>
<template>
<template is="dom-repeat" items="[[cars]] as="car>
...
<paper-button on-click="buttonClicked">Button</paper-button>
<paper-dialog id="dialog">
<h2>Title</h2>
</paper-dialog>
</template>
</template>
sample.dart
I'll omit the boilerplate code here, such as imports or the query to my database to fill the cars property ; everything works fine.
...
#reflectable
void buttonClicked(e, [_])
{
PaperDialog infos = this.shadowRoot.querySelector("#dialog");
infos.open();
}
This generates the following error :
Uncaught TypeError: Cannot read property 'querySelector' of undefined
I have tried several 'solutions', which are not, since nothing works.
The only thing I saw on quite a lot of threads is to use Timer.run() and write my code in the callback, but that seems like a hack. Why would I need a timer ?
I understand my problem may be that the content of the dom-repeat is generated lazily, and I query the items 'before' they are added to the local DOM.
Another advice I didn't follow is to use Mutation Observers. I read in the polymer API documentation that the observeNodes method should be used instead, as it internally uses MO to handle indexing the elements, but it again seems a bit complicated just to open a dialog.
My final objective is to bind the button of each generated model to a dedicated paper-dialog to display additional information on the item.
Has anyone ever done that ? (I should hope so :p)
Thanks for your time !
Update 1:
After reading Gunter's advices, although none of them actually worked by themselves, the fact that the IDs aren't mangled inside a dom-repeat made me think and query paper-dialog instead of the id itself, and now my dialog pops up !
sample.dart:
PaperDialog infos = Polymer.dom(root).querySelector("paper-dialog");
infos.open();
I now hope that each button will call the associated dialog, since I'll bind data inside the dialog relative to the item I clicked ~
Update 2:
So, nope, the data binding didn't work as expected: All buttons were bound to the item at index 0, just as I feared. I tried several ways to query the correct paper-dialog but nothing worked. The only 'workaround' I found is to query all the paper-dialog into a list and then get the 'index-th' element from that list.
#reflectable
void buttonClicked(e, [_])
{
var model = new DomRepeatModel.fromEvent(e);
List<PaperDialog> dialogs = Polymer.dom(this.root).querySelectorAll("paper-dialog");
dialogs[model.index].open();
}
This code definitely works, but it feels kind of a waste of resources to get all the elements when you really only need one and you already know which one.
So yeah, my initial problem is solved, but I still wonder why I couldn't query the dialogs from their id:
...
<paper-dialog id="dialog-[[index]]">
...
</paper-dialog>
#reflectable
void buttonClicked(e, [_])
{
var model = new DomRepeatModel.fromEvent(e);
PaperDialog dialog = Polymer.dom(this.root).querySelector("dialog-${model.index}");
dialog.open();
}
With this code, dialog is always null, although I can find those dialogs, correctly id-ied, in the DOM tree.
You need to use Polymers DOM API with shady DOM (default). If you enable shadow DOM your code would probably work as well.
PaperDialog infos = new Polymer.dom(this).querySelector("#dialog")

JQuery table sorter pager with AJAX - sorting not working ok

I have a problem with JQuery table sorter pager plugin.
I am trying to use paging with AJAX call. It seems to work OK for most cases, but I am unable to get the sorting working.
The problem is that when the request is made it always looks like (assuming the code from example here):
http:/mydatabase.com?page=0&size=100&{sortList:col}
just like the last parameter {sortList:col} is never actually replaced with proper sorting column.
If I'm reading the example correctly the request for sortList = [[2,0],[3,0]] should actually look like:
http:/mydatabase.com?page=0&size=100&col[2]=0&col[3]=0
But in my case it never is. Also when I click on the header the sorting is performed, but no request is made.
Is there anything I am missing in the linked example?
EDIT
The first part of my problem has been solved by replacing the plugin with the newest version.
For the second part, I still cannot get a request when clicking (sorting) columns. The ajaxProcessing function is almost exactly the same as in the example here, only headers variable is renamed.
As Mottie sugested I am posting an example result from AJAX call (MS MVC JsonResult):
{
"total_rows":1,
"headers":["Id.","Date","User name","File name","status","Hash","Link"],
"rows":[
{
"Id":"21",
"ReceiveDate":"02.12.2012",
"UserName":"John Doe",
"FileName":"test.txt",
"Status":"",
"Hash":"4A71FD2E12F7E04ED0C04E17476BD1BC5F823C8F",
"FileNameLink":"\u003ca style=\"padding-left:10px\" href=\"GetFile?Id=21&fileName=test.txt\"\u003eSave\u003c/a\u003e"
}]
}
Regards
I apologize, but I didn't get a chance to thoroughly test the latest changes to the pager. Some of the code was written by someone else, so I might have missed something obvious.
Anyway, this might be the bug that is causing you problems. It resets the table to the first page after each sort... I'll have fixed in the next update.
In the pager plugin, lines 460-470 is this code:
.bind('filterEnd.pager sortEnd.pager', function() {
//Prevent infinite event loops from occuring by setting this in all moveToPage calls and catching it here.
if ($.data(table, 'pagerUpdateTriggered')) {
$.data(table, 'pagerUpdateTriggered', false);
return;
}
c.page = 0;
updatePageDisplay(table, c);
moveToPage(table, c);
changeHeight(table, c);
})
Just change the c.page = 0 to this:
if (e.type === 'filterEnd') { c.page = 0; }
and add an e to the function(e).

Text URL in AIR iOS app not selectable

I'm using AIR 2.0 (soon will be updating to 3.3 with Flash CS6) to create an iPad app. We have textfields (Classic, dynamic) which sometimes contain one or multiple htmlText links which need to be clickable. In the desktop version of the program, all text is selectable and the links are easily accessed. My problem is that it takes me mashing the link like 20 times on the iPad before it will recognize that there's a link and navigate to it in Safari. The other strange thing is that none of the text appears to be selectable - I can't get the iPad cursor, copy/paste menu, etc. to show up.
I think, from reading other threads, that the hit area for the URL is only the stroke on the text itself... if that's true, what can I do to increase the hit area? Or make text selectable? It was suggested elsewhere to put movieclips behind the URLs but that's not really possible as this is all dynamic text from XML files.
I've read about StageText but I gather this is only used for input fields, which is not the case here.
I'm reasonably advanced in AS3 but I'd prefer an easy solution over re-writing large chunks of code. At the moment the only thing I can think to do is get the URL and make it so that as soon as you touch anywhere on the textfield, it navigates to the link. But this would break down if there were more than 1 URL in a given textfield.
Any ideas?
I had this exact same issue, and it's had me flummoxed for a while.
Here's what I did to get the desired behaviour:
1) Instead of using a listener for TextEvent.LINK, listen for MouseEvent.CLICK (or TouchEvent.TAP) on the TextField.
eg.
var tf:TextField = new TextField();
tf.addEventListener(MouseEvent.CLICK, linkClicked);
2) In the linkClicked() handler, you use getCharIndexAtPoint() to determine the index of the character that was clicked, and then from that determine the URL from the TextFormat of the character. This is adapted from a post by Colin Holgate on the Adobe Forums (http://forums.adobe.com/thread/231754)
public function linkClicked(e:MouseEvent):void {
var idx:int = e.target.getCharIndexAtPoint(e.localX, e.localY);
trace("Tapped:",idx);
var tf:TextFormat = e.target.getTextFormat(idx);
if(tf.url != "" && tf.url != null) {
var linkURL:String = tf.url;
trace(linkURL);
// Hyperlink processing code here
dispatchEvent(new UIEvent(UIEvent.LINK_TAPPED,tf.url));
}
}
3) The last line (dispatchEvent()) is sending a custom event to another function to process the link, but you could easily inline your code here.
I've tested on an iPad 3 running iOS6.1, building with AIR3.5. Links are much more responsive, and I don't find myself mashing the screen trying to hit the stroke of the text!

ie9: annoying pops-up while debugging: "Error: '__flash__removeCallback' is undefined"

I am working on a asp.net mvc site that uses facebook social widgets. Whenever I launch the debugger (ie9 is the browser) I get many error popups with: Error: '__flash__removeCallback' is undefined.
To verify that my code was not responsible I just created a brand new asp.net mvc site and hit F5.
If you navigate to this url: http://developers.facebook.com/docs/guides/web/#plugins you will see the pop-ups appearing.
When using other browsers the pop-up does not appear.
I had been using the latest ie9 beta before updating to ie9 RTM yesterday and had not run into this issue.
As you can imagine it is extremely annoying...
How can I stop those popups?
Can someone else reproduce this?
Thank you!
I can't seem to solve this either, but I can at least hide it for my users:
$('#video iframe').attr('src', '').hide();
try {
$('#video').remove();
} catch(ex) {}
The first line prevents the issue from screwing up the page; the second eats the error when jquery removes it from the DOM explicitly. In my case I was replacing the HTML of a container several parents above this tag and exposing this exception to the user until this fix.
I'm answering this as this drove me up the wall today.
It's caused by flash, usually when you haven't put a unique id on your embed object so it selects the wrong element.
The quickest (and best) way to solve this is to just:
add a UNIQUE id to your embed/object
Now this doesn't always seem to solve it, I had one site where it just would not go away no matter what elements I set the id on (I suspect it was the video player I was asked to use by the client).
This javascript code (using jQuery's on document load, replace with your favourite alternative) will get rid of it. Now this obviously won't remove the callback on certain elements. They must want to remove it for a reason, perhaps it will lead to a gradual memory leak on your site in javascript, but it's probably trivial.
this is a secondary (and non-optimal) solution
$(function () {
setTimeout(function () {
if (typeof __flash__removeCallback != "undefined") {
__flash__removeCallback = __flash__removeCallback__replace;
} else {
setTimeout(arguments.callee, 50);
}
}, 50);
});
function __flash__removeCallback__replace(instance, name) {
if(instance != null)
instance[name] = null;
}
I got the solution.
try {
ytplayer.getIframe().src='';
} catch(ex) {
}
It's been over a months since I last needed to debug the project.
Facebook has now fixed this issue. The annoying pop-up no longer shows up.
I have not changed anything.

jQuery UI dialog display inside frame, from bookmarklet?

I'm writing a bookmarklet which needs to work in the context of pages whose design I don't control. Some of the pages I need the bookmarklet to function in use frames (in framesets). Is it possible for a jQuery-UI dialog to work inside a frame?
Currently, when I encounter a page with a frameset, I creating my dialog like this:
var frame = window.frames[0];
var div = $(frame.document.createElement("div"));
div.html("My popup contents");
div.dialog( ... );
The result is that jQuery appends the ui-widget div to the main document, rather than the frame's document. Since the main document is just a frameset, nothing is displayed. I can't find any options in the jquery-ui API to specify which document the widgets should be constructed in. The bookmarklet will necessarily be running (or at least starting) from within the context of the outer document.
I'm aware that it won't be possible to display an overlay over the frames; I'm comfortable with display just in a single frame. Also, some other notable bookmarklets fail to function on pages with framesets, so this may be a common problem.
Suggestions?
Bookmarklets typically don't use jQuery. Most bookmarklets open a window which has jQuery.
Here's what I ended up doing: rather than attempting to display within or over a frame, I just had the bookmarklet rewrite the page to remove the framesets and add my own body and content to the page. This allows the bookmarklet to still introspect the frames and get data that it needs from them to construct the overlay prior to removing the framesets, but allows the overlay to still work.
Something like this:
if (window.frames) {
for (var i = 0; i < window.frames.length; i++) {
// ... grab data from the frame ...
}
}
if ($("frameset")) {
$("html").children("frameset").remove();
document.body = document.createElement("body");
$("html").append(document.body);
// ... add my stuff to body ...
}

Resources