javascript function not getting called - javascript

In a Django template, I have a function
function show_graph(i){
$("#"+i+"seegraph").click(function(){
$("#"+i+"graph").show();
var qaa = {{ question_ids }};
var qid = qaa[i-1];
jQuery.ajax({
url: "/canvas/recreatechart/",
type: "get",
data: {qid: qid },
success: function(response){
var resp = jQuery.parseJSON(response);
alert("chart1"+i);
show_graph("chart1"+i, resp['chart_type'], resp['series_names'], JSON.stringify(resp['data1']), resp['answer'], resp['stories1'], resp['colors'], resp['stacked'], resp['title1']);
show_graph(resp['second_graph']+i,resp['chart_type'], resp['series_names'], resp['data2'], resp['answer'], resp['stories2'], resp['colors'], resp['stacked'], resp['title2']);
}
});
});
}
and an alert immediately inside show_graph, from which I've deduced that show_graph just isn't getting called, but I don't know why.
I don't have any errors in my console, when I tried alerting each argument in the first call one by one, they all showed up as expected, although "data1" showed up as "object Object" with a type of "object" (When I stringified data1, it came out as expected, although I don't know if that means anything).
Note that data1 is an array of dictionaries, the values of which are arrays of arrays. So, slightly complicated, and I'm not sure if js can parse the structure.
Is that why my function is not getting called? If not, what is it? If so, how do I fix it (given that this is the format I have to pass my data in). How can I find the problem?
EDIT: I would also like to note that I just tested something simple like [5] in place of data1, as that's what I was afraid was messing up the function call, but I'm still not getting the alert from show_graph, so I think that's not it after all.

You're already inside of a function called show_graph. Instead of calling the function you want, it's calling itself, and adding another click action to...a jquery selector that doesn't match anything. So rename your inner function and everything should work.

Do you have more than one function called show_graph()? Is the intention for the function to call itself from within the ajax success callback?
The function you posted has one parameter, i:
function show_graph(i){ ... }
Within the function you seem to be treating i as a number, e.g., at the point where you say qaa[i-1]. But then within your ajax call your success callback calls show_graph like this:
show_graph("chart1"+i, resp['chart_type'], resp['series_names'], JSON.stringify(resp['data1']), resp['answer'], resp['stories1'], resp['colors'], resp['stacked'], resp['title1']);
I don't know if you intended for it to call itself, but you're not passing in a single numeric parameter, you're passing in lots of parameters. (Of course JavaScript lets you do that if you use the arguments object, but in your case you're passing a string as the first argument but as I said above the function treats it as a number.)

A few thoughts...
Your function show_graph(i) is expecting a single argument. In the way you're using it in your selectors (like $("#"+i+"seegraph")), we can assume that the i refers to a string or a number. Later, you're sending show_graph a list to use in place of i, by calling:
show_graph("chart1"+i, resp['chart_type'], resp['series_names'], JSON.stringify(resp['data1']), resp['answer'], resp['stories1'], resp['colors'], resp['stacked'], resp['title1']);
It sounds like you might have another function somewhere that needs to show a graph (perhaps a 2nd show_graph, while this function creates the graph?

Perhaps your Ajax is failing (for one of many possible reasons) and so it isn't calling the success callback? Try adding an error: callback to see if it is called.
As for the [object Object] bit, that is a side effect of alert-ing objects. alert() converts its arguments to strings and the default Object toString method returns that "[object Object]". Use console.log (or directly inspect values in the debugger) to avoid this problem.

I think the problems is, show_graph attaches a click event to an element
When the click event happens, the callback for click is called, which performs an ajax call.
In successful ajax call, you call show_graph again, expecting it to fully execute, but doesn't. It just attaches another click event listener (considering an element is found)
So, your show_graph shouldn't bind the click event.

Related

Can't access object property that's been set through an ajax call

Ok, I'm really at a loss here, and totally can't figure it out.
I have an object literal
say:..
In my object literal,
I call the function, get comments, a property of the object.
it turns an AJAX call on and in the AJAX success method,
I save the data , to self.commentsData
I have used
var self = this;
before the AJAX and therefore SELF refers to the object and not the AJAX.
But I cannot access this property from anywhere else.
I logged self to console, both from inside the AJAX and outside the AJAX and from another function in the object literal (the AJAX is also part of a function in the object literal)
and the weirdest thing shows:
inside the AJAX I see my object Class { with all the properties }
Outside the AJAX I see the object without the commentsData property,
However, if I click on it, the commentsData property does show in the drop down menu, just like it does in the other self log. Using self.commentsData however doesn't seem to work from anywhere in the object except for inside the ajax success method.
I'm really not sure what I'm doing wrong. This almost looks like a bug in javascript, or the chrome console. Has anyone ever seen this before ?
I would post my code but it's fairly long and contains many other functions and would be a tad tedious to look through.

Getting access to $(this) in jQuery's .on() data object?

I am using .on() to add listeners a few items in my DOM - one input range field, and a number of blocks with the class .colorBlock. These event listeners only need to be active intermittently, and I would like to turn them .off() when they are not in use. Doing this means using a named function instead of an anonymous one.
So fair enough, except that I need to pass data into the callback functions. I know I can use the second (third?) argument field to pass in an object to the event, which is readable in the callback, but doing so seems to be scoping this to the event, instead of to the DOM node that .on() was listened on. See below for example:
$('#brushSize').on('touchend', { size: $(this).val() }, utils.setBrushSize);
$('.colorBlock').on('touchstart', { color: $(this).data('color') }, utils.setColor);
In my callback functions, I added an alert for e.data.color and e.data.size, and both call out undefined.
To make matters worse, this is a phone gap app, so I am limited in my options to trace what is getting passed around, so some of what I am assuming could be wrong about what is going on.
Any suggestions?
Thanks.
Let's break down this line:
$('#brushSize').on('touchend', { size: $(this).val() }, utils.setBrushSize);
It's exactly the same (other than the variables) as this:
var sizeValue = $(this).val();
$('#brushSize').on('touchend', { size: sizeValue }, utils.setBrushSize);
E.g., you're calling $(this).val(), and then passing the result of calling it in as part of your data object. So unless this is already what you want to get the value from at that point, it's not going to work.
If you want to get some information from the element when the event happens, just put that code in your event handler. For example, looking at this line:
$('.colorBlock').on('touchstart', { color: $(this).data('color') }, utils.setColor);
It looks to me like you're trying to get the color from the .colorBlock element that was touched. If so:
$('.colorBlock').on('touchstart', function() {
utils.setColor($(this).data('color'));
});
Or if you're going to reuse it:
utils.setColorFromEventElement = function() {
utils.setColor($(this).data('color'));
};
and
$('.colorBlock').on('touchstart', utils.setColorFromEventElement);
Side note:
There's also a possible second problem with that line. You're using utils.setBrushSize as the event handler. Note that within the call to setBrushSize, this will refer to the DOM element on which you hooked the event, not utils. Now, given the name utils, maybe that doesn't matter, but I thought I'd mention it.
More: Mythical methods, You must remember this
The value you're sending in the arguments object is always going to be the number it was when you called the .on() statement. That function's not going to be dynamically re-called every time the event fires.
Personally I think it's really ugly to have the util class go looking for some DOM element and get its value, when as you alluded, what you really want to do is have your util function run in the same scope as the .on() statement.
Your first instinct was probably correct. You don't want an anonymous function, because you want to be able to call off(). Ideally you want a named function that runs in the same scope as the thing that calls the on() statement. So what you want to do is bind the util function to your current scope:
$('#brushSize').on('touchend', utils.setBrushSize.bind(this));
Then in utils.setBrushSize, $(this) is whatever function you called .on() from.
edit Just a warning on this though: when you call off(), you want to call it like this:
$('#brushSize').off('touchend', utils.setBrushSize);
Not on a new scope-bound version of setBrushSize. JQuery should recognize it as equal to the original function you bound and turn it off.
re-edit I'm realizing now that your val() is in $('#brushSize') as that's the "this" you're trying to call... not the function holding the on statement. In that case you can do it this way:
$('#brushSize').on('touchend', utils.setBrushSize.bind($(this)));
So the solution for this particular problem ended up requiring that I strip this bit of code out of Phone Gap and rebuild it in a browser. I was then able to console.log the event that was being sent to the callbacks, and examine them to understand the event object better.
The solutions was to use event.target. This allowed to get the event.target.dataset.color for the .colorBlock listener, and event.target.value from the brushSize range listener.
So for future me, I would be good to have a solid working version of my app in the browser with the phone gap stuff stripped out, to do better testing for problems like this.

ASP.NET Calling defined JS-function with RegisterStartupScript

In ASP.NET we are calling defined js-functions with the:
Page.ClientScript.RegisterStartupScript(GetType(), "", "JSFuncNameHere();", true);
I wonder:
Why there isn't any method, which has a name like: Page.ClientScript.CallJSScript("someJSFunc");
Why does the upper-method require the reflection method GetType() ? Something isn't defined at runtime, is it?
Why do I need the 2nd argument key? As I have tested, I can left it empty and the existed JS-function shall be called.
Why there isn't any method, which has a name like: Page.ClientScript.CallJSScript("someJSFunc");
Probably because this is more generic solution, since by just adding 2 characters you get the same result and if you need you can add arguments and anything else.
Why does the upper-method require the reflection method GetType() ? Something isn't defined at runtime, is it?
Why do I need the 2nd argument key? As I have tested, I can left it empty and the existed JS-function shall be called.
For both of these the same reason - the method will detect if you run the same script multiple times and in such case, call it just once. The two arguments are the means how it identifies duplicates - a key is not sufficient since another class in a different library might be using the same key - so you need to pass in the type of your own class to ensure that the script is executed when you want it to.

My javascript constructor function method returns the entire method as text, instead of the expected return value

I am new to constructor functions, and I have the following in a .js file I include:
// should just get the number of customers out of the passed-in object
function myCustomers(customerObj) {
this.customerCount = function(customerObj) {
return customerObj.length;
};
}
On the .htm page which includes the .js file, I have the following:
var tmpObj = new myCustomers(custObj);
alert(tmpObj.customerCount);
What I expected was the alert to give me the number of customers, such as "1", etc. Instead, the alert contains the entire text of my function as though it were a string, like this:
function(customerObj) {
return customerObj.length;
}
I'm sure this is simple, but I have had a tough time googling for an answer, since my search contains very generic words like function, text/string, method, etc. FYI, this example has been pared down from a more complicated function, to hopefully make it easier to understand the question. I have tested this simpler function with the same result.
Thanks in advance!
It looks like in your alert, you are not actually calling the function, but instead passing the function itself to alert(). Try this:
alert(tmpObj.customerCount(custObj));
You might also want to change your myCustomers object to hang on to the object that is passed into the constructor, so you don't have to pass it in again when you call the function.
You should call the method like this:
var tmpObj = new myCustomers(custObj);
alert(tmpObj.customerCount(custObj));
Note the method parenthesis ;)

DOJO difference between instantiation and using source

I am new to DOJO and trying to figure out the difference between these two uses of the seemingly two things.
dndController: new dijit.tree.dndSource("dijit.tree.dndSource",{copyOnly:true})
and
dndController: "dijit.tree.dndSource"
The second one works, but when I use the first one, it gives me an error when loading my tree. It says type node is undefined. The reason I want to use the first one though is because I want to set copyOnly to true.
Any answers appreciated it.
That parameter expects a constructor function instead of the object you passed. Perhaps the following would work:
dndController: function(arg, params){
return new dijit.tree.dndSource(
arg, // don't mess up with the first parameter
dojo.mixin({}, params, {copyOnly:true}))
//create a copy of the params object, but set copyOnly to true
}
Some explanation:
I actually don't know anything about drag-and-drop on trees. All I did was look at the Tree source code (its at dijit/Tree.js or something like that) to find out where dndController is used. From that point I could find out that is was supposed to be a function that can receive these two parameters (or a string representing the path to such a function...). The actual dijit.tree.dndSource function that is used I just copied from your question statement, hoping it would work.
The dojo.mixin function mixes in all the objects in its 2nd, 3rd, ... arguments into the first argument. By using a new, empty, object as the "receiving" object we have a neat way to make a shallow copy of params, settting copyOnly without modifying the original params object.

Categories

Resources