I'm trying to load KnockoutJS using the jQuery's getScript function and, after countless tests, I'm still stuck with the
ReferenceError: ko is not defined
error.
Here's a simple code that I'm running in my script to test if everything works (I've also tried to write this code directly into FireBug but I got the same results):
$.getScript('http://knockoutjs.com/downloads/knockout-3.2.0.js',
function(d,s,j){
console.log(d);
console.log(s);
console.log(j);
console.log(ko);
});
Checking the console shows those messages:
undefined
success
Object { readyState=4, status=200, statusText="success", other elements...}
ReferenceError: ko is not defined
and I've no idea on what's going on.
As a side note, I've also tried those urls with the same results
http://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js
http://knockoutjs.com/downloads/knockout-3.2.0.debug.js
EDIT:
Based on #T.J. Crowder's first answer I also tried this code
$("<script>")
.on("load", function() {
// It's loaded now
console.log("success");
})
.on("error", function() {
// It failed to load
console.log("error");
})
.attr("src", "http://knockoutjs.com/downloads/knockout-3.2.0.js");
but nothing is shown on the console.
getScript uses XHR (ajax), which is controlled by the Same Origin Policy. So you can't load scripts from other origins unless they enable your origin via CORS.
Instead, simply add a script tag referencing the script you want to load.
var scr = document.createElement('script');
scr.onload = function() {
display("Loaded: " + typeof ko);
};
scr.onerror = function() {
display("Error");
};
scr.src = "http://knockoutjs.com/downloads/knockout-3.2.0.js";
document.querySelector("script").parentNode.appendChild(scr);
function display(msg) {
$("<p>").html(String(msg)).appendTo(document.body);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Related
What I am trying to do?
I am trying to create a small javascript snippet that would run in my browser on youtube's subscriptions page (https://www.youtube.com/feed/subscriptions) and would allow to bulk add videos I have not watched into my "Watch Later" playlist so I can binge watch them in chunks and/or on my smartTV later.
How am I trying to do it?
I am trying to use Google Youtube Data API and modify "Watch Later" playlist by calling "insert" method.
What is the issue I am getting?
In order to do everything from above one of the things is to load google api script onto the page. And that is where I am seeing issue. When I load that script (https://apis.google.com/js/api.js) on a separately hosted HTML page (or just in jsfiddle sandbox) everything works:
<script>
function handleClientLoad() {
// Load the API client and auth2 library
gapi.load('client:auth2', initClient);
}
function initClient() {
// do nothing for now
}
</script>
<script async defer src="https://apis.google.com/js/api.js" onload="handleClientLoad()"></script>
However, when I try to do the same in my userscript using tampermonkey I am getting an error.
function loadScript(url, callback)
{
console.log('load script: ' + url);
// Adding the script tag to the body
var body = document.getElementsByTagName('body')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
script.async = true;
script.defer = true;
// Then bind the event to the callback function.
script.onreadystatechange = function() {
console.log('in readyStateChange. readyState: ' + this.readyState);
callback();
};
script.onload = function() {
console.log('in onload');
this.onload = function() {};
callback();
};
// Fire the loading
body.appendChild(script);
}
function initGAPI() {
console.log('initGAPI');
gapi.load('client:auth2', initClient);
}
function initClient() {
// do nothing for now
}
loadScript('https://apis.google.com/js/api.js', initGAPI);
I can see that my user script is being successfully triggered when I navigate to https://www.youtube.com/feed/subscriptions, however when it comes to gapi.load() method I am getting this error:
Uncaught TypeError: gapi.loaded_0 is not a function
at cb=gapi.loaded_0:1
I tried to inspect what is available on youtube's page before I load my own instance of gapi and realized there is already gapi object exists there and it has only one method: load(). When I try to call that method on that existing object (without trying to load my own instance of gapi script) it:
gapi.load('client:auth2', function() {console.log('gapi loaded');})
I get error of:
GET https://apis.google.com/_/scs/abc-static/_/js/k=gapi.gapi.en.HtLvrA_npCQ.O/m=client/exm=oauth2/rt=j/sv=1/d=1/ed=1/am=AAE/rs=AHpOoo8wHQU_A1WtgGgcOpQEfGjHuD8e-g/cb=gapi.loaded_1 net::ERR_ABORTED somewhere in desktop_polymer.js (line 2661)
I see there are different callbacks engaged (gapi.loaded_0 and gapi.loaded_0). However I can't make anything of it.
I am starting to think that I can't really use Google API while on google's own site (like youtube in my case). Is that correct assumption?
Maybe there are already existing solutions that achive my goal (bulk add non-watched videos into "Watch Later" playlist) - would appreciate any pointers :)
Turned out it was just my lazy eye. I missed the fact that I load https://apis.google.com/js/api.js twice. One time through #require external dependency - feature of tampermonkey script, another time - via dynamically adding that same script to the page as per instructions I started with to onboard with Google API.
Just loading via #require doesn't really work as that doesn't trigger callback that is necessary to instantiate everything properly. So I had to remove that directive and only rely on adding script to the page dynamically. After I did that - everything started to work. So, all in all, my code I posted in question is actually valid one to use, the problem was only in how I adopted it for usage in tampermonkey userscript :)
I have an HTML page where several JavaScript, CSS and images files are referenced. These references are dynamically injected and user can manually copy the HTML page and the support files to another machine.
If some JS or CSS are missing, the browser complains in the console. For example:
Error GET file:///E:/SSC_Temp/html_005/temp/Support/jquery.js
I need somehow these errors reported back to me on the inline JavaScript of the HTML page so I can ask user to first verify that support files are copied correctly.
There's the window.onerror event which just inform me that there's a JS error on the page such as an Unexpected Syntax error, but this doesn't fire in the event of a 404 Not Found error. I want to check for this condition in case of any resource type, including CSS, JS, and images.
I do not like to use jQuery AJAX to verify that file physically exists - the I/O overhead is expensive for every page load.
The error report has to contain the name of the file missing so I can check if the file is core or optional.
Any Ideas?
To capture all error events on the page, you can use addEventListener with the useCapture argument set to true. The reason window.onerror will not do this is because it uses the bubble event phase, and the error events you want to capture do not bubble.
If you add the following script to your HTML before you load any external content, you should be able to capture all the error events, even when loading offline.
<script type="text/javascript">
window.addEventListener('error', function(e) {
console.log(e);
}, true);
</script>
You can access the element that caused the error through e.target. For example, if you want to know what file did not load on an img tag, you can use e.target.src to get the URL that failed to load.
NOTE: This technically will not detect the error code, it detects if the image failed to load, as it technically behaves the same regardless of the status code. Depending on your setup this would probably be enough, but for example if a 404 is returned with a valid image it will not trigger an error event.
you can use the onload and onerror attributes to detect the error
for example upon loading the following html it gives alert error1 and error2 you can call your own function e.g onerror(logError(this);) and record them in an Array and once the page is fully loaded post is with single Ajax call.
<html>
<head>
<script src="file:///SSC_Temp/html_005/temp/Support/jquery.js" onerror="alert('error1');" onload="alert('load');" type="text/javascript" ></script>
</head>
<body>
<script src="file:///SSC_Temp/html_005/temp/Support/jquery.js" onerror="alert('error2');" onload="alert('load');" type="text/javascript" ></script>
</body>
</html>
I've put together the code below in pure JavaScript, tested, and it works.
All the source code (html, css, and Javascript) + images and example font is here: on github.
The first code block is an object with methods for specific file extensions: html and css.
The second is explained below, but here is a short description.
It does the following:
the function check_file takes 2 arguments: a string path and a callback function.
gets the contents of given path
gets the file extension (ext) of the given path
calls the srcFrom [ext] object method that returns an array of relative paths that was referenced in the string context by src, href, etc.
makes a synchronous call to each of these paths in the paths array
halts on error, and returns the HTTP error message and the path that had a problem, so you can use it for other issues as well, like 403 (forbidden), etc.
For convenience, it resolves to relative path names and does not care about which protocol is used (http or https, either is fine).
It also cleans up the DOM after parsing the CSS.
var srcFrom = // object
{
html:function(str)
{
var prs = new DOMParser();
var obj = prs.parseFromString(str, 'text/html');
var rsl = [], nds;
['data', 'href', 'src'].forEach(function(atr)
{
nds = [].slice.call(obj.querySelectorAll('['+atr+']'));
nds.forEach(function(nde)
{ rsl[rsl.length] = nde.getAttribute(atr); });
});
return rsl;
},
css:function(str)
{
var css = document.createElement('style');
var rsl = [], nds, tmp;
css.id = 'cssTest';
css.innerHTML = str;
document.head.appendChild(css);
css = [].slice.call(document.styleSheets);
for (var idx in css)
{
if (css[idx].ownerNode.id == 'cssTest')
{
[].slice.call(css[idx].cssRules).forEach(function(ssn)
{
['src', 'backgroundImage'].forEach(function(pty)
{
if (ssn.style[pty].length > 0)
{
tmp = ssn.style[pty].slice(4, -1);
tmp = tmp.split(window.location.pathname).join('');
tmp = tmp.split(window.location.origin).join('');
tmp = ((tmp[0] == '/') ? tmp.substr(1) : tmp);
rsl[rsl.length] = tmp;
}
});
});
break;
}
}
css = document.getElementById('cssTest');
css.parentNode.removeChild(css);
return rsl;
}
};
And here is the function that gets the file contents and calls the above object method according to the file extension:
function check_file(url, cbf)
{
var xhr = new XMLHttpRequest();
var uri = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = function()
{
var ext = url.split('.').pop();
var lst = srcFrom[ext](this.response);
var rsl = [null, null], nds;
var Break = {};
try
{
lst.forEach(function(tgt)
{
uri.open('GET', tgt, false);
uri.send(null);
if (uri.statusText != 'OK')
{
rsl = [uri.statusText, tgt];
throw Break;
}
});
}
catch(e){}
cbf(rsl[0], rsl[1]);
};
xhr.send(null);
}
To use it, simply call it like this:
var uri = 'htm/stuff.html'; // html example
check_file(uri, function(err, pth)
{
if (err)
{ document.write('Aw Snap! "'+pth+'" is missing !'); }
});
Please feel free to comment and edit as you wish, i did this is a hurry, so it may not be so pretty :)
#alexander-omara gave the solution.
You can even add it in many files but the window handler can/should be added once.
I use the singleton pattern to achieve this:
some_global_object = {
error: (function(){
var activate = false;
return function(enable){
if(!activate){
activate = true;
window.addEventListener('error', function(e){
// maybe extra code here...
// if(e.target.custom_property)
// ...
}, true);
}
return activate;
};
}());
Now, from any context call it as many times you want as the handler is attached only once:
some_global_object.error();
Hello,
I am trying to test error supression on Sharepoint but I am having some trouble.
This is my process:
On a relatively plain website (all it contains is a colored-in div), I added this script:
<script>
var x[] = 0;
var err = 10/x;
alert(err);
</script>
When setting my Outlook homepage to this site, I see this error:
I also have the following script, which suppresses this message (when adding this to my code, the error message doesn't appear):
<script type="text/javascript">
window.onerror = function(message, url, lineNumber) {
// code to execute on an error
return true; // prevents browser error messages
};
</script>
I want to test this script out on my Sharepoint site, but when I embed the above, error-inducing code onto my Sharepoint homepage and open the page in Outlook, I am not seeing any error messages.
I added the code in the following ways:
1 - Page > Edit > Edit Source > Added the code to the top
2 - Page > Edit > Embed Code > Added the code to various areas of the page
Neither of these methods worked, and the first one actually produced a message telling me that I should use the embed function, which also doesn't seem to work!
I need to generate this error from the Sharepoint page so that I can check **whether the error-suppressing script actually does what it's supposed to. Can **anyone think of what may be going wrong here?
Any help is much appreciated!
This is apparently a known issue in Sharepoint, and can be resolved by using the following function:
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function(){
//your code goes here...
});
For the purposes of the above test, I was able to generate an error with the following:
<script language='javascript'>
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', function(){
var x[] = 0;
var err = 10/x;
alert(err);
});
</script>
And adding the below suppressed the errors:
<script language='javascript'>
window.onerror = function(message, url, lineNumber) {
return true;
};
</script>
Note that this only worked for me after adding the 2 bits of code in their own, seperate <script> tags. I also had to add language='javascript' to the tags before it would work.
I added the code by embedding some new code, and adding both of the script tags to that web part. Because I was able to produce the error message, I was also able to prove that the error-suppression method worked.
I am having this issue due to using some third party script that is throwing me an error. The script relates to a wordpress plugin that has actually been published by the author.
I am using the 'iLightBox' plugin to display liteboxes for my images. However i need to set which images appear in the lightbox gallery. I have been using the developer website and found the following URL: http://www.ilightbox.net/faq.html
Script 5 appears to do what i need:
jQuery(document).ready(function(){
(function(){
var groupsArr = [];
$('[rel^="ilightbox["]').each(function () {
var group = this.getAttribute("rel");
$.inArray(group, groupsArr) === -1 && groupsArr.push(group);
});
$.each(groupsArr, function (i, groupName) {
$('[rel="' + groupName + '"]').iLightBox({ /* options */ });
});
})();
});
I am running this code in a custom.js file and i can see using 'inspect element' in Chrome that the file is loading correctly but the script is erroring with the following:
"Uncaught TypeError: $ is not a function".
I have read through some posts by other users who explain i need to encapsulate with a function and finish with '(jQuery)' however if i do this it just generates more errors.
Can anyone assist me?
My website where the error is showing: http://www.complete-models.com/uncategorized/16-alien-figure/
If you can change your code just replace $ to jQuery
$('[rel^="ilightbox["]').each(function () {
to
jQuery('[rel^="ilightbox["]').each(function () {
Make sure that you custom.js loaded after jQuery so in html file <scipt> tag for jQuery should be above custom.js
My website needs to use the Google Earth plugin for just a bit longer (I know, the API is deprecated, but I'm stuck with it for several more months). I load it by including google.com/jsapi, then calling google.load like so:
...
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("earth", "1", {"other_params": "sensor=false"});
google.setOnLoadCallback(function () {
// call some JavaScript to begin initializing the GE plugin
});
</script>
</body>
</html>
This works well from multiple computers and with multiple browser inside our company's firewall. It works well from my home computer, and from my colleagues' home computers. However, when my customer tries to load it, she gets an error message that google is not defined on the line that begins google.load(.
Of course, global variable google is defined at the start of file www.google.com/jsapi, so presumably that file isn't loading. I initially assumed that her corporate firewall was blocking that file, but when I asked her to paste "https://www.google.com/jsapi" into her browser's address bar, she said that immediately loaded up a page of JavaScript.
The entire output to the browser console is:
Invalid URI. Load of media resource failed. main.html
ReferenceError: google is not defined main.html:484
And I believe the Invalid URI business is just because we don't have a favicon.ico file.
She is running Firefox 35.0.1, though she says the same error occurred with IE (she didn't mention the version of IE).
Short of asking her to install Firebug, which I don't think is going to be feasible, how can I troubleshoot this issue?
I'm really not sure with that assumption but:
Could it be, that your first script loads asynchronous? Then for slow connections (your customer) this problem would occur (i know that you are not using the async tag - but maybe the source can trigger to load async).
Best thing to do here is to make sure that the Google code you're using is the sync kind and redeploy.
Also https://bugsnag.com/ can be a really interesting tool for you. Just implement the js and you can track every error your customer gets.
Redeploy your code as follows,
<script type="text/javascript">
try {
google.load("earth", "1", {"other_params": "sensor=false"});
google.setOnLoadCallback(function () {
// call some JavaScript to begin initializing the GE plugin
});
} catch (e) {
$.post('http://<your-remote-debug-script-or-service>',e)
}
</script>
Then, when your customer encounters the error, the full details will be sent directly to your server and you can troubleshoot as necessary.
It could be something as simple as the clients browser is blocking javascript from being executed. Maybe specifically blocking your domain or something crazy like that.
Can you try an external script that loads the google jsapi, then put your code in the callback to ensure it is loaded?
<script type="text/javascript">
function loadScript(url, callback){
var script = document.createElement("script")
script.type = "text/javascript";
if (script.readyState){ //IE
script.onreadystatechange = function(){
if (script.readyState == "loaded" ||
script.readyState == "complete"){
script.onreadystatechange = null;
callback();
}
};
} else { //Others
script.onload = function(){
callback();
};
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}
loadScript("https://www.google.com/jsapi", function(){
google.load("earth", "1", {"other_params": "sensor=false"});
google.setOnLoadCallback(function () {
// call some JavaScript to begin initializing the GE plugin
});
});
</script>
(Modified from http://www.nczonline.net/blog/2009/07/28/the-best-way-to-load-external-javascript/)
You may also want to look at jsapi Auto-Loading to minimize what is loaded, but it may get tricky with an older library. https://developers.google.com/loader/