I'm trying to asynchonously a Google Map. There are a lot of examples out there, but the ones a find use global(?) functions to showcase the concept of using callback function. The project I'm working on, however, defines various objects and uses prototypes to add properties/functions to them. The relevant source code looks as follows:
var Demo = new Array();
Demo.Content = function() { };
Demo.Content.prototype = { };
Demo.Content.Controller = function() {
this.contentView = new Demo.Content.View(this);
};
Demo.Content.Controller.prototype = {
initialize : function() {
this.contentView.initialize();
},
onGoogleMapsScriptLoaded : function() {
alert('onGoogleMapsScriptLoaded');
},
};
Demo.Content.View = function(controller) {
this.controller = controller;
};
Demo.Content.View.prototype = {
initialize : function() {
// now called from background script (Chrome extensions)
//this.asyncLoadGoogleMap();
},
asyncLoadGoogleMap : function() {
$.getScript("http://maps.googleapis.com/maps/api/js?v=3&sensor=false&callback=???")
.done(function (script, textStatus) {
alert("Google map script loaded successfully");
})
.fail(function (jqxhr, settings, ex) {
alert("Could not load Google Map script: " + ex);
});
},
};
contentController = new Demo.Content.Controller();
contentController.initialize();
While I get the success message "Google map script loaded successfully", I have no idea what to use as callback function -- always something is undefined. I tried, for example, contentController.test -- Cannot read property 'onGoogleMapsScriptLoaded' of undefined -- or indeed using a global function as in the examples on the Web. How do I set the callback function? Or do I have a more fundamental mistake here?
EDIT: The whole things is part of a content script for a Google Chrome extensions -- in case this important. This includes that I now load the map when the page is really finished loading using
chrome.tabs.onUpdated.addListener( function (tabId, changeInfo, tab) {
if (changeInfo.status == 'complete') {
chrome.tabs.sendMessage(tabId, {action: 'load-map'}, function(){});
}
});
in the background script. The content script has a message listener that invokes asyncLoadGoogleMap. So the page should be completely there. Still, I get the same errors.
Here is the code for AngularJS, but it still creates the global callback function:
// Google async initializer needs global function, so we use $window
angular.module('GoogleMapsInitializer')
.factory('Initializer', function($window, $q){
// maps loader deferred object
var mapsDefer = $q.defer();
// Google's url for async maps initialization accepting callback function
var asyncUrl = 'https://maps.googleapis.com/maps/api/js?callback=';
// async loader
var asyncLoad = function(asyncUrl, callbackName) {
var script = document.createElement('script');
//script.type = 'text/javascript';
script.src = asyncUrl + callbackName;
document.body.appendChild(script);
};
// callback function - resolving promise after maps successfully loaded
$window.googleMapsInitialized = function () {
mapsDefer.resolve();
};
// loading google maps
asyncLoad(asyncUrl, 'googleMapsInitialized');
return {
// usage: Initializer.mapsInitialized.then(callback)
mapsInitialized : mapsDefer.promise
};
})
Related
I am using Angular2 for a mobile app and I have to open a URL in a new window using one of the inbuilt cordova plugins (InAppBrowser). To detect the event upon which the page-loading of the new window completes, there is an EventListener "loadstop" as given below. This is from a component inside my app
var options = {url: "mylink", fileName: "myfilename"};
let browser = new InAppBrowser('http://www.myexamplesite.com', '_blank', 'location=no');
browser.on("loadstop")
.subscribe(
() => {
browser.executeScript(
{
code: "getOptions("+options+");"
});
},
err => {
console.log("Loadstop Event Error: " + err);
});
The external URL is a HTML file with some JavaScript code. The getOptions(options) is a JavaScript function defined there as inline. This is the function:
function getOptions(options) {
alert("Values are "+options['url']+" and "+options['name']);
}
But the function is not invoked in this way. It works when I remove the parameter options from both the call and the definition. What could be the reason? Are the objects in Angular2 and JavaScript not interoperable?
The problem is the way you are concatenating the string and options. You could use JSON.stringify to get something you can concatenate.
Illustration of the issue:
var options = {url: "mylink", fileName: "myfilename"};
// This is what you do:
console.log("getOptions("+options+");");
// This is what you should do:
console.log("getOptions(" + JSON.stringify(options) + ");");
//
// This shows it works: `getOptions` will be called.
//
function getOptions(options) {
console.log("OPTIONS: ", options);
console.log("Values are "+options['url']+" and "+options['fileName']);
}
eval("getOptions(" + JSON.stringify(options) + ");");
If you run the above, you get this on the console:
getOptions([object Object]);
getOptions({"url":"mylink","fileName":"myfilename"});
OPTIONS: { url: 'mylink', fileName: 'myfilename' }
Values are mylink and myfilename
I have been trying for a few days now to convert my tracking pixel JS functionality to use a 204 "no_content" response.
I can easily get this working, but I need to be able to fire a callback function afterwards.
The following doesn't seem to ever get fired once the 204 is returned.
beacon: function (opts) {
var beacon = new Image();
opts = $.extend(true, {}, {
url: pum_vars.ajaxurl || null,
data: {
action: 'pum_analytics',
_cache: (+(new Date()))
},
error: function () {
console.log('error');
},
success: function () {
console.log('success');
}
}, opts);
// Create a beacon if a url is provided
if (opts.url) {
// Attach the event handlers to the image object
if (beacon.onerror) {
beacon.onerror = opts.error;
}
if (beacon.onload) {
beacon.onload = opts.success;
}
$(beacon).on('load', function( response, status, xhr ){
alert(status);
});
// Attach the src for the script call
beacon.src = opts.url + '?' + $.param(opts.data);
}
}
The tracking is logged properly, but no alert or console log messages. Is this possible or am I just wasting my time?
Edit ------
Based on the solution below here is the final version (this assumes that both an error & success will use the same callback.
beacon: function (opts) {
var beacon = new Image();
opts = $.extend(true, {}, {
url: pum_vars.ajaxurl || null,
data: {
action: 'pum_analytics',
_cache: (+(new Date()))
},
callback: function () {
console.log('tracked');
}
}, opts);
// Create a beacon if a url is provided
if (opts.url) {
// Attach the event handlers to the image object
$(beacon).on('error success done', opts.callback);
// Attach the src for the script call
beacon.src = opts.url + '?' + $.param(opts.data);
}
}
You aren't attaching any callbacks to image. Your test if (beacon.onerror) results in false because beacon.onerror is null.
You should use if( "onerror" in beacon ) to tests whether beacon has onerror property.
But why dont you just use jquery's method on?
$(beacon).on("error", function() {
alert("Jquery error");
});
$(beacon).on("done", function() {
alert("Jquery done");
});
I want to be able to run scripts grabbed from one place, in another. I have access to these scripts using the following jQuery:
element.each(function(){
var script = $(this).find('script');
// I want to run contained scripts here.
});
I am just unsure how to use these objects to run the scripts they contain (are).
An example of an inline script I have to re-run (from a third party)
<script language="javascript">
interact.embedApp({
target: "bame", width: 1, height: 1,
vars: {id: "1", resolveJSPath:"true"},
params: {allowScriptAccess: "always",base:"http://",deepLinking:"false",wmode: "transparent"},
src: [
{type:"html5", src:"http://", xd: ["http://"]},
{type:"swf", src:"http://",version:"0"}
]
});
</script>
You appear to be including inline script content, albeit content that has been provided by a third party.
In this instance you can wrap the body of the code that they have supplied in your own function:
<script>
var invoke = invoke || []; // make sure the array exists
invoke.push([function() {
// third party code goes here
}, [arg1, arg2]]); // optional arguments
</script>
and then any time after that (including the first time!) when you want to call all the functions:
function invokeAll() {
return invoke.map(function(a) {
var f = a[0];
var args = a.slice(1);
var ctx = a[2];
return f.apply(ctx, args);
});
}
You can use the Blob object (see MDN). Here's a function using it:
function getInlineJS(elem) {
var js = elem.textContent;
var blob = new Blob([js], {"type": "application\/javascript"});
return URL.createObjectURL(blob);
}
This jsFiddle uses it to create a web worker
Like #Alnitak remarked, this can only be applied to inline script tags. If the originating scr server has enabled CORS it should be possible to retrieve scripting source code using XHR e.g. something like:
$.ajax( {
url: [the src url]
,method: 'get'
,success: function(data) { /* ... */ }
} );
I'm using Django.
I have the following code
var done_cancel_order = function(res, status) {
alert("xpto");
};
var cancel_order = function() {
data = {};
var args = {
type:"GET",
url:"/exchange/cancel_order/"+this.id,
data:data,
complete:done_cancel_order
};
$.ajax(args);
return false;
};
The function var cancel_order is called when I press a button on the page. That url when accessed is does some things on the server side, which I can check indeed are done, and then returns a json specifying whether or not the request was successful. You get:
{'status':200, 'message':'order canceled'}
The problem is that the callback is never called. I would like to have the callback display to the user the thing that was returned from the server. But even the first alert("xpto") inside the callback is never executed. Why is that?
EDIT:
I have checked that this code:
var cancel_order = function() {
data = {};
var args = {
type:"GET",
url:"/exchange/cancel_order/"+this.id,
data:data,
complete: function() { alert("xpto"); }
};
$.ajax(args);
return false;
};
displays the same behavior as described above: everything goes great on the server side, but the callback isn't called.
Be sure nothing is messing with your debug tools [e.g. console.log], it may end up wrecking your js code, delivering unexpected results.
Why don't you change it to this:
function done_cancel_order (res, status) {
/* remains same */
};
I hope, this one would work for you!
Or just simply:
complete: alert("xpto");
I am writing a Javascript SDK to interact with a web service. I am using jQuery to do my AJAX calls.
When an AJAX call fails, I have registered an event handler for the ajaxError that gets called at the top of my .js file. My problem, and I don't understand why, is that when it gets called I have no way of accessing class member variables for my Akamanda.Client.
I tried adding another method for Akamanda.Client as .prototype.logError, which got called by the jQuery Ajax handler, but even then a test for (this.logging) failed as well.
How can I access class member variables from jQuery callbacks? What am I failing to understand here? Akamanda.Client.logging is undefined from the ajaxError callback.
My code for the SDK:
$(document).ajaxError(function(event, jqxhr, settings, exception) {
// more robust error handling for different conditions
if (Akamanda.Client.logging) {
console.log('FAILED: ' + settings.type + ' ' + settings.url + ' => ' + exception);
}
});
Akamanda.Client = function(options) {
this.URL = options.URL || 'http://m-test.akamanda.com';
this.baseURL = this.URL + '/api/' + Akamanda.API_VERSION;
this.feedsURI = '/websyndication/feed/';
// who is the client? (iphone/android/web)
this.clientName = options.clientName;
// For development: Logging and buildcurl IS ON, for production: OFF
//this.logging = options.logging || true;
this.logging = true;
// called when a user is not authorised (Disabled)
// this.logoutCallback = options.logoutCallback || null;
}
Akamanda.Client.prototype.getFeeds = function(callback){
var feeds = [];
$.getJSON(this.baseURL + this.feedsURI, function(data) {
$.each(data, function(index, feed) {
feeds[index] = {
name: feed.name,
title: feed.title,
link: feed.link
};
})
callback(feeds);
});//.error(function(err) { (disabled at the moment in favour of ajaxError event)
// console.log('Error: ' + err.error);
// });
}
My code for the client (in another JS source file):
var options = { logging: true };
myAPI = new Akamanda.Client(options);
var feeds = [];
var articles = [];
function getFeeds()
{
myAPI.getFeeds(function(AkamandaFeeds) {
feeds = AkamandaFeeds;
showFeeds();
});
}
As far as I can see from the code you posted, you are never instantiating an object of type Akamanda.Client.
var Client = new Akamanda.Client();
or
var Akamanda.Client = {};
Akamanda.Client.logging = ....
JSBin Example: http://jsbin.com/ajidig/1/edit
Ok, here a little example(real code but very simplified):
//we wrap our code in a self invoking function so that we don't pollute the global namespace, see http://stackoverflow.com/questions/6715805/self-invoking-functions-javascript for further details
(function(){
//create your object that holds all your function, that are different ways to do this
var Akamanda = {};
//a private function
function ErrorHandler(clientObj) {
this.clientObj = clientObj;
//do whatever with clientObj
this.log = function(){..}
}
//private constructor for clientobj
function Client(options){
..
}
Akamanda.Client = function(){
var newClient = new Client({..});
//setup
Akamanda.ErrorLogging = new ErrorHandler(newClient);
return newClient;
}
//bind our service to the window object to make it accesible
window.Akamanda = Akamanda;
})()
//client
var myAPI = Akamanda.Client();
Akamanda.ErrorLogging.log();
I hope this basic examples helps. If you need to know more about Javascript Patterns, I can recommend this book http://jsninja.com/ by John Resig, the creator of jQuery.
Depending on what you want to do, there's also a lot of frameworks like http://backbonejs.org/ that help with this kind of stuff.