Dear All,
I'm using dojo.declare to create classes in JavaScript. In one of the methods, I've an AJAX request. In the load method of that request, I need to execute certain methods.These methods are actually methods of the class that was created using dojo.declare. I tried to execute the method using this. But it gave me method not found error. So I used dojo.hitch(this,testMethod) to invoke it. It worked fine. Now the problem is I've lot of other methods also inside testMethod() which internally calls other methods of my JavaScript class. It is really a pain to have dojo.hitch() everywhere. Is there any work around for this.
dojo.declare("TestClass",null,{
getData:function(url){
dojo.xhrGet({
url:url,
load: function (response){
dojo.hitch(scope of the current object,testMethod(response))
},
error:function(){
}
});
},
testMethod:function(response){
//calls testMethod2. I think I can use dojo.hitch(this,testMethod3) to call it.
//but I wanted to avoid doing it every time.
},
testMethod2:function(){
//calls testMethod3
},
testMethod3:function(){
//can call other methods.
}
});
It seems like that execution scope was lost in this code:
load: function (response){
dojo.hitch(this,testMethod(response))
},
I made small changes in your code. Now it should work properly.
dojo.declare("TestClass",null,{
getData:function(url){
dojo.xhrGet({
url:url,
load: dojo.hitch(this,this.testMethod),
error:function(){
}
});
},
testMethod:function(response){
this.testMethod2();
},
testMethod2:function(){
this.testMethod3();
},
testMethod3:function(){
//can call other methods.
}
});
This is a typical context problem. You are passing an uncontexted function as a property of a configuration hash, which is passed as argument to dojo.xhrGet.
dojo.hitch is exactly the right construct to add a context to a function. Another way is to simply use a closure. Is there any reason why you can't do:
var me = this;
dojo.xhrGet({
url:url,
load: function(response) {
me.testMethod(response);
}
});
Try doing it like this:
dojo.xhrGet({
url:url,
load: dojo.hitch(this, "testMethod"),
error:function(){
}
});
Your way worked as well, but it saves you a few bytes and is just cleaner to use the method name as a string. Hitch will automatically pass the arguments for you.
Related
I have two functions in jQuery that I want to fire in a specific order. The first function is an ajax function which updates a partial view. The other one is supposed to do some styling on the partial view, once the ajax function has completed - this function takes a parameter.
ajaxFunction();
stylingFunction(params);
I have tried the following:
ajaxFunction(function() {
stylingFunction(params)
});
Also, I have tried to use a callback:
ajaxFunction(stylingfunction(params));
ajaxFunction(callback)
{
//Do update
callback()
}
None of these do however work. The styling appears shortly where after it dissapears because the partial view is getting updated. Where am I going wrong here?
Both functions are written in my "parent" view.
You can use .done() and .fail() chained to the $.ajax call ...
I created a couple callback functions with psuedo-code inside the successCallback() since you said you only need to run the styling function "sometimes". You will want to test whatever condition inside that function to determine if you want to run the styling function. Hope this helps.
(function($) {
$(function() { //document.ready
$.ajax({ cache: false,
url: "/blah/vlah/lah",
data: { somedata: somedata }
})
.done(successCallback)
.fail(failCallback);
});
function successCallback(data) {
if (someCondition) {
stylingFunction(params);
}
};
function failCallback(jqXHR, status, error) {
console.log(jqXHR);
console.log(error);
console.log(status);
};
})(jQuery);
I created another gist which handles ajax event delegation, you may want to review and incorporate anything that seems helpful to your situation.
https://gist.github.com/inceptzero/a753d020648f49da90f8
I also created this gist on github for an ajax request queue which is a bit more elegant and robust.
https://gist.github.com/inceptzero/e64756f9162ca6aeeee5
Since you are using jQuery you could const ajaxFunc = callback => $.ajax({...}).done( data => callback) Also you could use async/await. You can read more about it on MDN.
After my previous question, I come up to the following working code that is intended to refresh the DOM periodically by replacing the <div id="test_css_id">...</div> itself. The behavior of both AJAX requests present in the below code is to reload the same code itself.
<div id="test_css_id">
<a id="link_css_id" href="test_url.html">LINK</a>
<script type="text/javascript">
var refreshTimer;
$('#link_css_id').click(function(event) {
event.preventDefault();
$.ajax({
url: $(this).attr('href'),
type: 'PUT',
success: function(data) {
clearInterval(refreshTimer);
$('#test_css_id').replaceWith(data); // Replaces all code including JavaScript with the response data (note: the response data is exactly the same as the code shown here).
}
});
});
$(document).ready(function() {
function refreshFunction(){
$.ajax({
url: 'test_url.html',
type: 'GET',
success: function(data) {
clearInterval(refreshTimer);
$('#test_css_id').replaceWith(data); // Replaces all code including JavaScript with the response data (note: the response data is exactly the same as the code shown here).
}
});
}
refreshTimer = setInterval(refreshFunction, 1000);
});
</script>
</div>
However, as said by the author of the accepted answer, "there are other ways you can do it [..] one way is to wrap all of that code into a module". I am not expert in JavaScript but I would like to understand and learn it a little more.
How can I wrap all of that code into a module in order to avoid using global variables?
Your current code looks like this:
var refreshTimer; //a global variable
$(...).click(...);
To make refreshTimer not global, you need to put it inside a function:
function main(){
var refresherTimer; //this variable is now local to "main"
$(...).click(...);
}
main();
However, doing it this way won't solve the problem completely. While we did get rid of the global variables, we added a new one - the "main" function itself.
The final trick is to turn the "main" function into an anonymous function and invoke it directly. This is the famous "module pattern":
(function(){
var refreshTimer; //local variable to that anonymous function
$(...).click(...);
}()); //and here we call the function to run the code inside it.
The extra parenthesis around everything are important. If you do just function(){}() instead of (function(){}()) then you will get a syntax error.
Here's a nice description of the module pattern in JavaScript.
I am trying to call a function inside of a button click event.
$('#btn_save').button().click(function(){
executeStatement();
});
$.fn.executeStatement = function(){
alert("Here!!!");
$.ajax({
url: 'api.php',
data: sqlStatement,
dataType: 'json',
success: function(data)
{
alert("Success!!!");
}
});
}
The problem is that it never gets called because it is undefined according to the debugger: Uncaught ReferenceError: executeStatement is not defined
Can someone give me a hint what is wrong?
Thanks in advance
Unless you are trying to make a jQuery plugin (which I don't think you are?), change your function declaration to:
function executeStatement(){
//code here
}
Just to elaborate on the previous answer, $.fn is kind of like jquery's namespace. Anything that starts with $. is part of jquery. You can actually add functionality to jquery by adding functions to $.fn, but it's probably not what you want.
I found this really confusing at first too, so I thought I'd try to clarity.
Curt's answer is completely correct. But I thought I would add to it.
function executeStatement(){}
this is called a function declaration and will work in this case.
var executeStatement = function(){};
this is called a function expression and will also work in this scenario.
How can I use setTimeout() in a Backbone model?
I have the next code:
var ContentModel = Backbone.Model.extend({
URL: "http://localhost/example.php",
requestType: "POST",
dataType: "json",
data: "", //Set the value outside the model
startSend: function (Data) {
//
},
reply: function (Data) {
var dataJson = eval(Data);
console.log(dataJson);
setTimeout(this.ajaxRequest(),4000);
},
problems: function (Data) {
//
},
ajaxRequest: function () {
$.ajax({
async:true,
type: this.requestType,
dataType: this.dataType,
url: this.URL,
data: this.data,
beforeSend:this.startSend,
success: this.reply,
timeout:4000,
error:this.problems
});
}
});
Alternatively I have tried:
setTimeout(function(){
//ajax code
},4000);
But the result is the same. setTimeout() don't work. The request only run once.
A couple of things are amiss. First off, this line:
setTimeout(this.ajaxRequest(),4000);
Should be:
setTimeout(this.ajaxRequest, 4000);
The first line of code executes the ajaxRequest function and passes the result (which is undefined) to setTimeout. That means the ajaxRequest function will execute once, but too soon. The latter line does what you want, which is to pass the function itself to setTimeout, and ajaxRequest will be called 4 seconds later.
But that's not quite enough. When the ajaxRequest function is executed, the value of this context is incorrect. When you called setTimeout, the context of the callback is set to window. You can verify this by console.log(this) in the callback function.
To fix it, you need to bind the context of the function. Since you're using Backbone, you've also got underscore.js already loaded. Using _.bind oughta do it:
setTimeout(_.bind(this.ajaxRequest, this), 4000);
Edit:
Come to think of it, there might be another problem. When the ajax call succeeds or fails, the reply or problems functions may suffer from the same loss of context as ajaxRequest did. But if there is, it's easily fixed.
Instead of calling _.bind on those too, the simplest way is to call _.bindAll in your Backbone model constructor.
initialize: function() {
_.bindAll(this, 'ajaxRequest', 'reply', 'problems');
}
When you call _.bindAll, underscore guarantees that every time any of the listed methods of your model is called, the this context variable points to the model itself, unless specifically bound to something else.
You don't need to do anything special to use setTimeout with backbone. Check the scope of this in your reply function. My guess it that this.ajaxRequest() isn't in scope.
You have to use setInverval instead.
setInterval(this.ajaxRequest, 4000);
setTimeout Triggers the function once.
setInterval Triggers each n ms.
var interval = setInterval(this.ajaxRequest, 4000);
clearInterval used to clear setInterval.
clearInterval(interval);
Or pass the context parameter on your ajax:
$.ajax({
...
context: this,
...
});
I'm using JqGrid and for each row in the grid I'm loading, I am making an ajax call to get additional data.
Once that's all complete, I need to apply some formatting.
I would like to use $.when(), but I'm not sure how to call it. I was researching the apply() method, but I still don't see how to use it appropriately.
Here is my code:
$(rows).each(function () {
$.ajax(
{
url: url,
data: data,
success: function (result) {
}
}
});
});
$.when(**What do i pass here??**).done(function () {
});
I had tried pushing each $.ajax call to an array, but I can't pass the array directly, and call everything.
Thanks in advance for your help!
This may not work at all, in fact I'm curious as to whether or not it will. Try building the array of promise objects, then call $.when.apply(null, arr).done(function () { ... });
apply allows you to trigger a function and pass an array of arguments dynamically, such as in this case.