Weird Javascript IOS 7 Issue - javascript

I have a web application which behaves fine on all desktop browsers and mobile devices however since IOS 7 I am encountering a weird issue.
Example:
I am setting an object like
(function(){
//CONSTRUCTOR*
sampleObject= new function(){
alert("loaded constructor "+ new Date().getTime()); //only outputted once
//swfobject dom load event
}
...//functions and propeties related to sampleObject
})();
//ASSIGNING THE OBJECT
sampleObject = new sampleObject();
alert("finished assigning object "+ new Date().getTime()); //only outputted once
Issue:
On ios 7 it seems to randomly lose what sampleObject is and instead reverts to what is inside the snippet with constructor*. So for example, I have been debugging it at intervals where I am calling a public method on my object such as sampleObject.getResource("a");
And the traces are coming back like:
sampleObject = [Object] //Correct
sampleObject = [Object]
and then randomly it does this:
sampleObject = function(){
//swfobject dom load event
}
Which basically is the code inside the constructor*.
This then causes my code to throw a reference error as the public properties/methods which I am using throughout such as getResource are not defined...
Things Tried:
Code only initiates once (alerts fire once with single Date / random string)
I Identified where an error was occuring due to this issue, wrapped around a try/catch however although the code is clearly failing it is not going into the catch.
Tried it on different IOS versions, all fine except IOS 7
*CONSTRUCTOR - not sure if this is classified as a constructor but that is what it seems to me.
**Unfortunately I cannot post my code publicly as it is part of a commercial project and quite extensive.... However any suggestions or has anyone had any similar issues?
Thanks!

Thanks for all the comments above. That pointed me in the right direction.
The problem seems to be that IOS 7 seems to randomly loses scope of the javascript object, and because we werent specifically assigning the sampleObject to the window then it wasnt working all the time.
Therefore solution to my problem was simply to change:
//ASSIGNING THE OBJECT
sampleObject = new sampleObject();
to
//ASSIGNING THE OBJECT
window.sampleObject = new sampleObject();

Related

Running client side javascript without loading a new (blank) view on Odoo 8

I need to run some client-side javascript from a button in a form view in Odoo 8. This button runs a python method which returns this dictionary:
{"type": "ir.actions.client",
"tag": "my_module.do_something",}
do_something is defined in a .js file as follows:
openerp.my_module = function (instance) {
instance.web.client_actions.add("my_module.do_something", "instance.my_module.Action");
instance.my_module.Action = instance.web.Widget.extend({
init: function() {
// Do a lot of nice things here
}
});
};
Now, the javascript is loaded and executed properly, but even before launching the init function, Odoo loads a brand new, blank view, and once the javascript is over I can't get browse any other menu entry. In fact, wherever I click I get this error:
Uncaught TypeError: Cannot read property 'callbackList' of undefined
What I need instead is to run the javascript from the form view where the button belongs, without loading a new view, so both getting the javascript stuff done and leaving all callbacks and the whole environment in a good state. My gut feeling is that I shouldn't override the init funcion (or maybe the whole thing is broken, I'm quite new to Odoo client-side js) , but I couldn't find docs neither a good example to call js the way I want. Any idea to get that?
Sorry, I don't work on v8 since a lot of time and I don't remember how to add that, but this might help you: https://github.com/odoo/odoo/blob/8.0/doc/howtos/web.rst
Plus, if you search into v8 code base you can find some occurence of client actions in web module docs https://github.com/odoo/odoo/search?utf8=%E2%9C%93&q=instance.web.client_actions.add
Thanks to the pointers simahawk posted in another answer, I have been able to fix my js, which is now doing exactly what I needed. For your reference, the code is as follows:
openerp.my_module = function (instance) {
instance.web.client_actions.add("my_module.do_something", "instance.my_module.action");
instance.my_module.action = function (parent, action) {
// Do a lot of nice things here
}
};

IE8 crashes with AngularJS and dynamic content

I have the following code:
<blockquote class='mt20'>
<p><span>“</span><span>{{iq.quote}}</span><span>”</span></p>
<footer><cite class="dark-grey">{{iq.author}}</cite></footer>
</blockquote>
For some reason, this is causing IE8 to crash. I've done a lot of debugging and have found that when the the iq object contains just the quote:
{quote:"some quote"}
the browser doesn't crash. It only crashes with both quote and author.
I use a special function to get my data. It looks like:
this.get = function(){
var arr = {};
if(!arr.length){
$http.get('url').success(function(data){
$.extend(arr, data);
});
}
return arr;
}
I use this because the object is automatically bound so I don't have to watch it. It appears that the crash happens on the extension of the data to the object when the view tries to update. Any thoughts?
I was able to fix this by changing from content bindings using {{}} to ng-bind.
<blockquote>
<p><span>“</span><span ng-bind="iq.quote"></span><span>”</span></p>
<footer><cite ng-bind="iq.author"></cite></footer>
</blockquote>
I have a hypothesis that the HTML5 footer element, combined with the {{}} content binding and the dynamic update caused a memory leak that crashed IE8 but I can't prove this. I do know that when the content is set and not changed (like what would happen if you used $http.get instead of my method), the browser doesn't crash. I also was using:
var obj = {}
and:
delete obj.key
I changed this to:
var obj = new Object()
based on this post: https://markfeimer.wordpress.com/2014/05/23/internet-explorer-8-javascript-delete-keyword-bug/

Issue with retrieving object data on IE 8 on Windows XP or 2003

This is an interesting problem that I am facing with JavaScript and IE8 on Windows XP and Windows 2003. I create an object on the page and then retrive information about that object (for example, its version). When trying to get the version, I am running this code:
var myObject = document.getElementById(objectId);
console.log(myObject.version);
What is interesting is that this code works on every single browser except IE8 on Windows XP and 2003. I've done some debugging and this is where things get interesting.
myObject is not null but myObject.version is undefined. So what I did is I added an alert in between so the code is now as follows:
var myObject = document.getElementById(objectId);
alert(myObject.version);
console.log(myObject.version);
The alert results in "undefined", however, the console.log is now resulting in the actual version. If I add an alert before this alert of anything (let's say alert("something")) then the second alert has the actual version now. I am assuming this is a timing issue (for some reason the object needs sometime to be able to provide the data stored in it?) but I am not sure what kind of timing issue this is or how to approach it.
Sorry for the long description but any help is appreciated.
document.getElementById doesn't return an object. It returns a DOM element. So, you expect to see a .version property in a DOM element, which by the official W3C specification is missing (or at least I don't know about this).
I'm not sure what you are expecting to see in .version, but if it is something custom then you should create a custom object like that:
var o = { version: "..." }
console.log(o);
You said that this may be a time issue. If that's true then I'll suggest to try to access the .version property after the DOM is fully loaded. You can use jQuery for the purpose:
$(document).ready(function() {
var myObject = document.getElementById(objectId);
alert(myObject.version);
console.log(myObject.version);
});
You can add a setTimeout in your function till the .version property is there.
var f = function(callback) {
var check = function() {
var myObject = document.getElementById(objectId);
alert(myObject.version);
console.log(myObject.version);
if(typeof myObject.version !== "undefined") {
callback(myObject.version);
} else {
setTimeout(check, 1000);
}
}
setTimeout(check, 1000);
}
What happens if you put the <script>...</script> tag with the js code at the end of the html file? In my opinion, the code is executed when the DOM is not ready. If you put it in the end, then it will be executed after it's loaded.

Monkey patch not firing. (Guess this Monkey cant punch ducks.)

I am trying to patch the JsonRest query method. Nothing I do seams to have an effect. Below I would expect the query method to no longer work and just write "monkey punching a duck." out to the console. But alas the entire app keeps on working ignoring my blatant attempt to break it. Do I need to patch a specific instance?
dojo.require("dojo.store.JsonRest");
(function(query, options){dojo.store.JsonRest.query=function(){console.info("monkey punching a duck.");};})();
aprStore = new dojo.store.JsonRest({"target":"/web/rest/apr/","idProperty":"ID"});
var sqry = "?nq=aquerytorun";
aprStore.query(sqry).then(function(result){});
The main goal is I want at the underlying xhrGet so I can attach a callback to the error property. The .query(function,function) is ignoring my error function passed in as the second parameter. http 302 is what is driving me nuts at the moment.
It's not 100% clear what you're trying to do, but I suspect you need to put your function on the prototype object of that JsonRest thing:
dojo.store.JsonRest.prototype.query = function() { ... };
Then instances made from that constructor will have access to your "query" function.

"Error calling method on NPObject!" in Uploadify

I'm using Uploadify to upload file in my CMS. Everything works fine until recently. I got an error
Error calling method on NPObject
on this line
document.getElementById(jQuery(this).attr('id') + 'Uploader').startFileUpload(ID, checkComplete);
on this part
uploadifyUpload:function(ID,checkComplete) {
jQuery(this).each(function() {
if (!checkComplete) checkComplete = false;
document.getElementById(jQuery(this).attr('id') + 'Uploader').startFileUpload(ID, checkComplete);
});
},
I don't know why and after a day debugging and testing I found that if I remove replace(/\&/g, '\\&') from
String.prototype.escAll = function(){
var s = this;
return s.replace(/\./g, '\\.').replace(/\?/g, '\\?').replace(/\&/g, '\\&');
};
It then works again. I really don't know why.
Any helps would be appreciated!
I think the reason is in additional Javascript libraries you use.
Some libraries (for example Prototype.js or jQuery.js) change behaviour of your code. For example, you can't overload prototype in some cases. The result may be undefined in clear (obvious) places (like you use an array variable with wrong index). You should view the source code of additional libraries, probably they do with prototype something that breaks your code in the function you mentioned.
In my practice I had the situation when overloading of prototype worked incorrectly (it was String prototype like in your case).
So just don't use prototype.

Categories

Resources