jQuery AJAX cross-module communication(module pattern) - javascript

I recently refactored my javascript/jquery application code to use the module pattern.
I have two modules, lets say A and B.
Module B contains a public method(say, Bmethod) that makes a jQuery AJAX JSONP call($.ajax) and passes the response in a callback.
Inside Module A there is a call to B.Bmethod() with a callback function to handle the returned response.
Here is module B's definition:
var B = (function()
{
var obj = {};
obj.Bmethod = function(data, callback)
{
//do JSONP AJAX call
callback(response);
}
return obj;
}());
Now, here's module A's definition with the method call on module B
var A = (function()
{
var doAjax = function(data)
{
B.Bmethod(data, function(response)
{
//Do something with the response
});
}
}());
Here's how I load the module A and start the code execution:
$(document).ready(function()
{
A.doAjax(data);
});
The problem here is that, I have different behavior on Chrome and Firefox. On Chrome, the AJAX call is not being executed at all. There is no request sent. However, on Firefox, I can see the request made and also get a response back, but I do not receive a success callback.
If I put all of this code outside of modules, in just one single file, everything seems to work properly.
I have seen a lot of people(on StackOverflow as well) using the module pattern with AJAX calls successfully, but have not been able to figure out what I am doing wrong.
Any ideas/solutions?

Fixed the problem.
I was actually having a duplicate copy of the same AJAX request($.ajax) in a different file. So, when the request was being made, I am assuming the duplicate was (also)being called, and maybe this was causing inconsistency issues. However, on Chrome, setting a breakpoint showed no signs of the duplicate being called.
For now, I removed the duplicate request and it works fine. But, I still don't understand why there was an inconsistent behavior between Chrome and Firefox.

Related

Javascript require returns empty object

I am trying to use a library found on the web, called himalaya, which is an html parser.
https://github.com/andrejewski/himalaya
I followed their guide on importing the library, so I do
var himalaya = require('himalaya');
However when I call one of its member functions, I get an error
TypeError: himalaya.parse is not a function
I tried executing himalaya.parse() on the web browser console directly, it works. I tried commenting out the require statement in the js file, the function no longer works on web browser.
I guess this implies the require statement works? But for some reasons I cannot use it in my javascript file, only on the browser console.
Perhaps something with file scopes? Here is part of my code.
var himalaya = require('himalaya');
Template.main.onCreated(function () {
var http = new HttpGet("www.someurl.com/", "/somedirectories/", function (response) {
console.log(himalaya.parse(response.content));
});
http.sendRequest();
});
I am certain that response.content does contain a valid html string.
When you call the himalaya.parse inside the main.onCreated function it seems like the library is not completed loaded at that time. That's why it only runs in your browser console. Check if the himalaya library has a onReady function to let you know exactly when you can use it. If not, you can:
a) Call the parse function inside the main.onRendered or
b) Keep the parse call inside the main.onCreated and set a timeOut to call it after a half second like this:
var himalaya = require('himalaya');
Template.main.onCreated(function () {
var http = new HttpGet("www.someurl.com/", "/somedirectories/", function (response) {
setTimeout(function(){himalaya.parse(response.content)},500);
});
http.sendRequest();
});
If you have an issue with the setTimeout check this answer:
Meteor.setTimeout function doesn't work

passing variables through callback functions in node.js

I posted this question yesterday but I guess I just confused everyone. I got responses like "what exactly is your question?" So I am expanding and reposting today.
The following node.js snippet is from the file "accounts.js" which is in an ETrade api library that exists in the path /lib. It should return json containing data about the accounts of the authenticated user. The authentication part is working great. I'm confused about what exactly is being done in the last line of this function:
this._run(actionDescriptor,{},successCallback,errorCallback);
Ten years ago (the last time I was coding), we didn't have the construct "this" and I haven't a clue about "_run" and Google searches have not been helpful. Here is the function.
exports.listAccounts = function(successCallback, errorCallback) {
var actionDescriptor = {
method: "GET",
module: "accounts",
action: "accountlist",
useJSON: true,
};
this._run(actionDescriptor, {}, successCallback, errorCallback);
};
I understand that the function is accessed with "et.listAccounts ...." but then my understanding goes all to hell. It's pretty obvious that a get is being executed and json data returned. It's also obvious that the result is passed back through the successCallback.
In my app.js file, I have the following:
var etrade = require('./lib/etrade');
var et = new etrade(configuration);
Can someone please suggest a snippet to be used in app.js that will output the accounts data to the console?
It seems like the json data must be passed back through the successCallback but I'm lost on how to access it on the app.js side.
Suppose in app.js I want to put the accounts data in a variable called myAccounts. The exports.listAccounts function does not specify a return value, so I doubt I can do var myAccounts = et.listAccounts(). Likewise, myAccounts will be undefined if I try to do this: et.listAccounts(){myAccounts, error}. Finally, the listAccounts function contains two possible variable names I could use, "accounts" and "accountlist" but these turn out to be undefined at app.js.
When I put a function in successCallback in app.js to write a generic message to the console, the message appears in the log so I know I am making it into the listAccounts function and back successfully. In this case, the log also shows
"Request: [GET]: https://etwssandbox.etrade.com/accounts/sandbox/rest/accountlist.json"
From this I deduce that the data is actually being returned and is available at that end point.
Ten years ago (the last time I was coding), we didn't have the construct "this" and I haven't a clue about "_run"
this refers to the current object, further reading here. _run is just what they chose to call the function.
I have no experience with this module, but with a cursory glance at the git repo I suspect you will want to expand your app.js like so:
et.listAccounts(function(response) {
console.log(response);
});
In javascript functions are first order and so can be passed around like variables see here. listAccounts wants a function passed to it, and when it is complete it will call it with one parameters, as can be seen in etrade.js.
There is also the function errorCallback which is much the same but is called on an error. You could expand the above snippet like so:
et.listAccounts(function(response) {
console.log(response);
}, function(error) {
console.log(error);
});

Why is console.log() not working client-side when inside Meteor methods?

I want to define the same method for both client and server, so I have the following code inside common/methods.js.
Meteor.methods({
doSomething: function (obj) {
if(this.isSimulation) {
console.log('client');
}
if(!this.isSimulation) {
console.log('server');
}
console.log('both');
return "some string";
}
});
Then I called this method inside client/dev.js.
Meteor.call('doSomething', someObj, function (e, data) {
console.log(e);
console.log(data);
});
On the server's console, I can read:
I20150622-21:56:40.460(8)? server
I20150622-21:56:40.461(8)? both
On the client's (Chrome for Ubuntu v43.0.2357.125 (64-bit)) console, the e and data arguments are printed, but the console.log() from the Meteor method is not, where I expected it to output the strings
client
both
Why do console.log() not work on the client inside Meteor methods?
To debug, I split the Meteor.methods into separate client and server code. Then introducing a large loop so the server-side operation so it takes a long time to complete, while the client-side is very quick.
server
doSomething: function (obj) {
var x = 0;
for(var i = 0; i< 9999999; i++) {
x++;
}
console.log(x);
return "some string";
}
client
doSomething: function (obj) {
console.log('client');
}
Still, no message is printed on the client.
Thanks to #kainlite for helping me debug this together. It turns out the problem was a simple one of file load order.
I defined my methods in common/methods.js, whereas my client-side calls were made in client/dev.js, which gets loaded first.
So when the call was made the method wasn't defined, hence it won't run. Moving the methods.js file inside the /lib directory fixed the issue.
Methods are only executed on the server, they are the sync way of doing a remote call.
Methods
Methods are server functions that can be called from the client. They
are useful in situations where you want to do something more
complicated than insert, update or remove, or when you need to do data
validation that is difficult to achieve with just allow and deny.
http://docs.meteor.com/#/basic/Meteor-users

yeoman generator: copy or template doesn't work from inside async callback

Inside a yeoman generator I am trying to do a conditional copy depending on the state of an external network resource. My problem is that the yeoman copy command (src.copy and template too for that matter) does not seem to do anything when invoked inside of an async callback, such as one from a http request.
Example code, inside of the yeoman.generators.NamedBase.extend block:
main: function(){
//-> here this.copy('inlocation','outlocation') works as expected
var that = this;
var appName = ...
var url = ...
var req = http.request(url, function(res){
//-> here that.copy('inlocation','outlocation') DOES NOT work
res.on('data', function (data) {
//console.log('Response received, onData event');
//-> here that.copy('inlocation','outlocation') DOES NOT work
});
//-> here that.copy('inlocation','outlocation') DOES NOT work
});
req.on('error',function(error){
//...
});
req.end();
//-> here this.copy('inlocation','outlocation') works as expected, once again
Note the locations marked by '//-->' comments for points of reference - when it works, it works as expected. When it doesn't, there's no output on console whatsoever (so that.copy seems to exist as a function, in fact I can assert that typeof that.copy === 'function' !), no error messages, just no file created (the usual file create message is missing too which is a characteristic of the properly working command).
Using call or apply to pass an explicit this reference to the functions didnt change the behaviour, nor did binding this to the async functions.
What is the explanation to this behaviour, and how can I make copy calls in this async manner?
As per Eric MORAND's comment, I'll post the solution I found as a separate answer, instead of an edit to the original post, hopefully it'll be easier to find:
I've found a solution, using the async() function of the yeoman RunContext. (see the api docs here) The following line at the beginning of the async code:
var done = this.async();
then a call to done() right before I wanted to run copy made it behave as originally expected.

Wrapping Backbone sync requests

I am writing a Backbone application, and I need to offer some feedback to users whenever a request to the server is made (annoying, I know, but I have no control over this behaviour of the application). The backend always reports an informative (at least in theory) message with every response, like
{
"status":"error",
"message":"something went really wrong"
}
or
{
"status":"success",
"message":"congratulations",
"data":{...}
}
What I would like to understand is where to put a hook for some kind of messaging service.
One possibility is the parse() method for models and collections. To avoid duplication, I would have to put it inside some model base class. It is still a bit annoying since all models and collections have their own parse() anyway.
A more reasonable place to look would be the Backbone.sync function. But I do not want to overwrite it, instead I would like to wrap it inside some other helper function. The problem here is that I cannot find a good hook where to put some logic to be executed with every request.
Do you have any suggestions on how to organize some piece of logic to be executed with every request?
Since Backbone.sync returns whatever $.ajax returns, it is easy to achieve what I want by using jQuery delegates, like this
var originalMethod = Backbone.sync;
Backbone.sync = function(method, model, options) {
var request = originalMethod.call(Backbone, method, model, options);
request.done(function(msg) {
console.log(msg);
});
request.fail(function(jqXHR, textStatus) {
console.log(jqXHR, textStatus);
});
return request;
};
Assuming you are using a recent (>1.5) jquery all results from sync will return the $.ajax promise.
You can do it then without overriding anything in sync by using that promise. For example, if you did a fetch(), you could do:
var p = mymodel.fetch();
p.done(function (res) { ... });
p.fail(function (err) { ... });
Of course you can also use callbacks in fetch options, but I find the above much cleaner. The same pattern applies for say save or anything that uses sync.

Categories

Resources