How to use JSONP with Object Oriented Javascript - javascript

I am new to JSONP and had implemented cross domain functionality for my application and everything is working fine. Now i want to change my javascript code to apply object orientation.
My api is
http://localhost:8080/myApplication/getComments?callback=displayComments
CrossDomain.prototype.displayComments = function(data) {
// code to display the comments
}
Now I am getting an error in firebug given below
ReferenceError: displayComments is not defined
I changed the api to
http://localhost:8080/myApplication/getComments?callback=this.displayComments
and found that the function is appended inline to the callback like this
http://localhost:8080/myApplication/getComments?callback=callback=function (jsonData)
{
//code to display the comments
}
this time another error in firebug
SyntaxError: function statement requires a name
I have a doubt whether to use JSONP in object oriented javascript or not.
Please help.
Thanks in advance.

There's no point in defining the function on the prototype of a function unless you are going to create instances of that function, so start by doing that.
var myCrossDomain = new CrossDomain();
Then you have to call the method on the object, not as a global (it isn't a global, so you can't do that anyway)
var uri = "http://localhost:8080/myApplication/getComments?callback=" +
encodeURIComponent("myCrossDomain.displayComments");
In response to edits and comments:
Yes i am creating an instance of this in another js file
Then reference it as shown above.
I changed the api to
http://localhost:8080/myApplication/getComments?callback=this.displayComments
It's JSON-P. It runs by adding a new script element. Everything gets called in the global context. That is going to call this.displayComments which will be the same as window.displayComments.
If you want to call your method directly, then you need to specify the global variable holding the instance explicitly.
If you don't want to call it directly then you can use the more traditional approach of generating a new, anonymous function which has access to said object through a closure, assigning that function to a global variable (with a unique name) and using that name as your callback argument.
and found that the function is appended inline to the callback like this
http://localhost:8080/myApplication/getComments?callback=callback=function (jsonData)
You haven't shown us the code that creates the URI so we can't tell why that might be the case.

Related

Can a Javascript function be called via wildcard?

In Javascript, if a function is referenced that doesn't exist, I can catch the resulting error using:
window.onerror = function(msg, src) {
// insert logic here
return true;
}
By parsing the content of msg, I can determine what function the developer was trying to call, and then by creating a Proxy object, I can prepare the app to ingest the arguments passed to the non-existent function that was referenced should the same function be called again.
However, it'd be ideal if I could handle the reference the first time it occurs. I'm interested in knowing if there's a way to either capture the arguments in the error handler, or if it's possible to declare a "wildcard" function that could respond when an undefined function is referenced.
Does such a thing or methodology exist?
Thank you in advance for your consideration and time.

Callbacks usage with instanced objects in Javascript

I was facing a problem with callbacks in Javascript. I solved my problem using what I would call an ugly property of Javascript (so to say, something that would logically be forbiden and never work in other languages than Javascript). So my question: Is there an ELEGANT way, to do the same thing.
I will so begin with the beginning. My goal was to wrap, in some manner, the Web Audio API. In the architecture, I implemented a class, lets call it AudioRessource, which is destined to be an interface (abstraction) in some manner of the AudioBuffer object of the Web Audio API.
This class (AudioRessource) have a prototype member function that must simply take an url as argument to automatically load audio data, decode it, handle errors, etc and finally hold the resulting AudioBuffer object in a "pseudo-private" member:
function AudioRessource()
{
this._aBuffer = null; // future reference to `AudioBuffer` object
this._loadStatus = 2;
};
AudioRessource.prototype.loadData = function(url) {
/* deal here with async functions to
provides audio data loading automation */
}
The main problem here, is that this will be an object instance (of AudioRessource) which will create the callback functions, using only local references, and must be able to pass the final AudioBuffer object to itself.
To load the raw audio data, this is pretty simple, I use the XMLHttpRequest object, with an extra property set as member of the XMLHttpRequest object, like this:
AudioRessource.prototype.loadData = function(url) {
let req = new XMLHttpRequest();
req.extraProperty = this; // reference to `AudioRessource` instance
req.onload = function(){
// retrive instance reference within the callback
this.extraProperty._loadStatus = 0;
}
req.onerror = function(){
// retrive instance reference within the callback
this.extraProperty._loadStatus = -1;
}
req.open('GET', url, true);
req.send(null);
this._loadStatus = 1;
}
The big problem appear when we have to decode the coded raw audio data into PCM data, that is, an Web Audio API AudioBuffer object instance. Indeed, the Web Audio API provides only one function to achieve this, and this function is asynchronous, and takes a callback that simply recieve the resulting buffer as argument: how to "catch" this resulting buffer to assign it to the proper AudioRessource instance (the one who lauched the process) ? This work that way:
AudioCtx.decodeAudioData(rawData,
function(result){
// do something with result },
function(error){
// do something with error });
My first naive approach, was to think like we were in C/C++ : I simply put an AudioRessource instance function "pointer" (reference) as callback, this way, the AudioRessource instance will directly recieve the buffer:
// where 'this' is an `AudioRessource` instance
AudioCtx.decodeAudioData(rawData,
this._handleDecodeSuccess,
this._handleDecodeError);
However, this does not work, because in javascript, this is not a "function pointer" that is passed into the decodeAudioData, but if I well undstand, an literal expression, that is, the "ASCII content" of the function... So the 'this' reference is lost !
I spent some time to try understand how this kind of asynchronous function is attended to work, since to me, coming from C/C++, this is simply an heresy: The function does not take any extra argument, no way to pass any external reference... "What is that thing ?". Then I finaly decided to try the "Illogical Javascript logic" way... And I found the solution :
// Create local variable which stores reference to 'this'
let thisInstReference = this;
// Use the local variable to write our callback
AudioCtx.decodeAudioData(rawData,
function(resut){
thisInstReference._aBuffer = result;
thisInstReference._loadStatus = 0;
},
function(resut){
thisInstReference._loadStatus = -3;
});
To be honnest, to me, this is simply freaking. First of all, I even don't understand what realy happen: HOW a local variable (to a object instance's member function), that stores a reference to an object instance (this), can be used "as this" in a callback function ? I do not even understand how a language can allow this kind of thing. Secondly, to me, this not a "proper way" to code something: this code is simply illogical, dirty, this works but this appear as an ugly hack that takes advantage of Javascript misdesign.
So here is my question: How to achieve this, in a elegant way ?
Your problem is simply due the the nature of how this works in javascript. The value of this is not bound at compile time nor at runtime but instead very late at call time.
In the following code:
AudioCtx.decodeAudioData(rawData,
this._handleDecodeSuccess,
this._handleDecodeError);
.. the value of this inside _handleDecodeSuccess and _handleDecodeError is not determined at object creation time but instead at the time they are called. And it is the decodeAudioData method that will eventually call them when decoding is complete. This causes the value of this to become something else (depending on how the functions are called).
The modern solution is to statically bind this to the functions:
AudioCtx.decodeAudioData(rawData,
this._handleDecodeSuccess.bind(this),
this._handleDecodeError.bind(this));
Note: the .bind() method creates a new function that wraps your function with this permanently bound to the argument you pass to it.
The traditional solution is to capture this inside a closure like what you have done.

Javascript * is not a function (prototype function)

Coming from a C++ background, trying to work with an OO language that doesn't have explicit typing is a little more than a headache.
So I have dynamic elements for a webpage that are "controlled" by objects since there are tons of stuff I need to manage on each for it to work. The element is just the visual output of the data inside of the object itself, that's all I really need it for.
Except that I need the object to perform an internal function when it's clicked. That seems to be the biggest source of my headache thus far.
Javascript:
function onClick(file) //The external onClick function I use to try to get it to call from.
{
file.state = INUSE;
file.checkState();
}
function fileObject () { //The file object itself
this.element;
this.newElement();
//initialize stuff for the object
}
fileObject.prototype.newElement = function() { //creates a new element and sets its event listener
this.element.click(function() {onClick(this)});
}
fileObject.prototype.checkState = function() {/*does stuff*/} //apparently this is "not a function"
The error I get exactly is "file.checkState is not a function" from Firefox's console panel.
I'm still new to javascript, but after doing some debugging, I've come to find out that it's explicitly the onClick(this) function that is causing all of the errors. When used with something else, the onClick function works perfectly, but for some reason, the this keyword doesn't appear to actually be sending the reference to the fileObject since all checks show file being undefined when inside of the onClick scope.
Is there something fundamentally wrong about the way I'm trying to do this or am I just missing a step (or adding something that I don't need) that will help get this snippet working.
So you know, your initial problem isn't actually handling the action, but listening to it. click will trigger a synthetic click event, rather than liste for one.
You want ... .element.addEventListener("click", callback); that said, you face a second problem, immediately thereafter.
I will leave my example code as you've written it to not confuse the matter...
But when you see click( ) know that I mean subscribing with addEventListener, if element really does mean a browser DOM element. If it's not a standard browser element, and your own API, then ignore the previous portion, and carry on.
this is dynamically bound at the invocation time of the function (not at definition time).
The nearest function, scoped above, is your callback function that you are passing into .click( ... ).
Which is entirely different than the this which you mean outside of the callback.
Whatever is on the left-hand side of the dot is the this context for the duration of that particular invocation.
Needless to say, click() doesn't know enough to bind the this you mean, to the left-hand side of your callback.
The solution (or one of many) is to use lexical scoping and/or closure to retain the value of the object you mean.
// easy but messier
var fileObject = this;
... .click(function () { onClick(fileObject); });
// Cleaner with thunks:
function clickHandler (onClick, obj) {
return function () { onClick(obj); };
}
... .click(clickHandler(this));
Coming from c++ the way Javascript handles this will seem a little crazy, it looks like here you need to tell the function you've defined what this is - like so:
this.element.click(function() {onClick(this)}.bind(this));

Changing the current closure?

I am trying to get some old code to work properly with minimal modification. The code was written on the assumption that it would run from a particular context. I have the context object.
Original code:
function oldExample(){
console.log(window); //New Error: window is undefined
console.log(gBrowser); //New Error: gBrowser is undefined
}
New, working code:
function fixedExample(){
console.log(this.window);
console.log(this.gBrowser);
}
//Elsewhere
function loadData(context) {
fixedExample.call(context);
}
Notes:
1. loadData and oldExample are defined in separate files.
2. context has other children besides window and gBrowser; This is an example
Is there a way to transition my oldExample code to work properly without needing to stuff this. everywhere? I.e., how can I run oldExample in a different context?
The only way I know how to do this is to define the properties as variables of the current context:
var object = {gBrowser: 'test'};
function oldExample(){
console.log(gBrowser);
}
var gBrowser = object.gBrowser;
oldExample();
This example outputs 'test'
But all this does is move the property access outside of the function definition, doesn't save you anything.
You can use bind method in javascript.
fixedExample.bind (context);
Now you need not use 'this' inside fixedExample and can use window directly.

javascript - how to call a function newly added from ajax

I have a coding difficulty which have been asked in this forum before:
Calling a JavaScript function returned from an Ajax response
But I didn't find the answers quite satisfying. To be more precise of the problem I'm dealing, here is the detail:
I dynamically load a document (HTML and javascript) using jquery
var url = 'document.php';
$('#container').load(url);
Example of what the document.php looks like:
<form>
<input name="firstname"></input>
</form>
<script>
function dosomething()
{
console.log($('input[name=firstname]').val());
}
</script>
*The dosomething() function is the one I'd like to call later
And then I want to call the functions from that document.php. Due to my requirement, I don't want to call the function after the documents' loaded, but rather to call it later when I need it. Because it was dynamically loaded, the DOM doesn't recognize the functions. How to properly call this function?
Thank you
the DOM doesn't recognize the functions
This sounds like your other functions are wrapped in $(document).ready() in the remote page. If that is the case they are out of scope for you to call them from code in the main page and you need to move them out of the ready handler to make them globally accessible.
EDIT: Other possibilities
Script tags in head- move to body after html, or use $.getScript in ajax callback to retrieve
I think that you're trying to implement the technique called on-demand javascript (or lazy-loading). In other words, your page should initially load just a small script - but use a bunch of objects and functions, which are available in some other files, but will be loaded when they're required.
If that's the case, I have to warn you: you'll probably need to update your existing code. Instead of just calling some function right as it is, in all gun-blazing glory, you should check for its existence first - and if it's not available, wait for its loading:
if (typeof lazyObjects.someLazyFunction !== 'function') {
lazyLoad('lazyFunction.js');
}
lazyObjects.someLazyFunction();
The key point here is that lazyLoad should be synchronous. In other words, you'll have to wait until the script containing your function is actually loaded. Otherwise someLazyFunction just won't be defined when it's called, even with this sort of checks.
lazyFunction.js, in turn, will contain some code that will alter lazyObjects, adding to them the required method as a property:
// in lazyFunction.js
lazyObjects.someLazyFunction = function() { ... }
While it's technically possible to use global (=window) object for these cases, I usually don't do this - and won't recommend doing it either.
See, it's not that simple. ) I'd recommend reading this article to find out more about this technique - and actually using some established components to implement it in your code (some of them are mentioned in the linked article).

Categories

Resources