jQuery passing arguments to callback not working on .keyup() - javascript

I made a simple autocomplete feature as follows:
$(document).ready(function(){
$('#search-field').keyup(function(e) {
ajaxAutocomplete(e);
});
});
function ajaxAutocomplete(e) {
var hash_tag = $.trim($(this).val());
$.ajax({
url : 'autocomplete.php',
method : 'GET',
dataType: 'html',
data : {tag : hash_tag}
})
.done(function(response) {
if (response) {
$('.datalistPlaceholder').html(response).show();
} else {
$('.datalistPlaceholder').hide();
}
})
.fail(function() {
alert('Something went wrong');
});
}
I am trying to use the event object in ajaxAutocomplete function as described by jQuery: https://learn.jquery.com/about-jquery/how-jquery-works/
The above set up does not work and returns this: jquery.js:7328 Uncaught TypeError: Cannot read property 'toLowerCase' of undefined
This does work after removing the callback from above:
$(document).ready(function(){
$('#search-field').keyup(ajaxAutocomplete);
});
function ajaxAutocomplete() {
var hash_tag = $.trim($(this).val());
$.ajax({
url : 'autocomplete.php',
method : 'GET',
dataType: 'html',
data : {tag : hash_tag}
})
.done(function(response) {
if (response) {
$('.datalistPlaceholder').html(response).show();
} else {
$('.datalistPlaceholder').hide();
}
})
.fail(function() {
alert('Something went wrong');
});
}

After combining Rory's answer above and reading about .call() from MDN I came up with the following that works:
$(document).ready(function(){
$('#search-field').keyup(function(e) {
ajaxAutocomplete.call(this, e);
});
});
function ajaxAutocomplete(e) {
console.log(e)
var hash_tag = $.trim($(this).val());
$.ajax({
url : 'autocomplete.php',
method : 'GET',
dataType: 'html',
data : {tag : hash_tag}
})
.done(function(response) {
if (response) {
$('.datalistPlaceholder').html(response).show();
} else {
$('.datalistPlaceholder').hide();
}
})
.fail(function() {
alert('Something went wrong');
});
}
Result on typing 'a':
j…y.Event {originalEvent: KeyboardEvent, type: "keyup", timeStamp: 1292.2500000000002, jQuery21406902543265129839: true, keyCode: 65…}

When calling a function, the context this gets lost. If you use the callback directly, the context is available.

The problem with your first example is because you wrap the call to ajaxAutocomplete() in an anonymous function which means that you lose the reference of this within your called function (it will point to the window instead of the #search-field element). This in turn means that $(this).val() returns nothing - hence the error coming from jQuery.
You need to either use .call(this) when calling your function to maintain the scope of this within the function:
$(document).ready(function(){
$('#search-field').keyup(function(e) {
ajaxAutocomplete.call(this);
});
});
Working example
Alternatively you can use your second method which passes the ajaxAutocomplete function reference to the event handler which then maintains scope:
$(document).ready(function(){
$('#search-field').keyup(ajaxAutocomplete);
});
Personally I prefer the latter approach for its brevity.

Related

Remake ajax function

Is there a way to make a function that converts default ajax function.
This is the ajax function i have
$.ajax({
type: "POST",
url: "http://" + document.location.host + '/userajax',
data: 'type=register&name=' + name,
beforeSend:function() {
},
success: function(response) {
}
});
This is what i want it to look like
ajax('url', {
method: 'get',
parameters: {
name: $('#name').val()
},
beforeSend: function() {
},
success: function(transport) {
}
});
Ive tried to search on the internet but did not find anything
Sure, you can create the function like this:
function ajax(url, params){
// everything is now available here
console.log( url ); // output: http://www.google.com
// you can get the data of the params object like this
console.log( params.method ); // output: get
// you can execute the beforeSend like this:
params.beforeSend();
// additionally you might want to check everything.
// maybe if the method is NOT set, you want it to always use GET
switch(arguments.length) {
case 1: url = throw new Error('Url should be set');
case 2: params.method = 'get';
case 3: break;
default: throw new Error('illegal argument count')
}
}
You would call this like:
ajax('http://www.google.com', {
method: 'get',
parameters: {
name: $('#name').val()
},
beforeSend: function() {
// some function
},
success: function(transport) {
// some function
}
});
This certainly is possible, it's just a bit of work. Some of the basics you need:
First of all, you need a good understanding of the XMLHTTPRequest API, you can find more info on that on MDN.
Next, finding out how to do a callback, that is actually quite simple, you can pass an anonymous function reference as an option or attribute for a function. That goes like this:
function doSomething(variable, callback){
variable = variable + ' something'; // just doing something with the variable
callback(variable);
}
// then call the function with a callback (anonymous function)
doSomething('doing', function(result){ alert(result); });
You should get an alert that says 'doing something'.
And finally you should know how to read an object, passed as 'options' in the ajax function. Say you have a function like this:
function foo(url, options){
console.log(url);
console.log(options.method);
console.log(options.parameters.name);
}
// call it like this
foo('https://google.com/', {
method: 'get',
parameters: {
name: 'myName'
}
});
That should log the url, method and parameters in the console.
Now from here, you should have all the pieces to put the puzzle together. Good luck!
I don't think so. but you can do this:
$(document).ready(function(){
var parameters = {
name: $("#name").val(),
desc: $("#desc").val()
};
$.ajax({
url: 'path/to/file',
data : parameters,
beforeSend: beforeSubmit,
dataType: "json",
type : 'POST',
})
.done(function(data) {
})
.fail(function() {
console.log("error");
})
})
Also note I don't set the function for the beforeSend directly in the call, I will create an externe function which gives me more freedom.
so I could do this:
function beforeSubmit(){
if(something !== 'somethingelse'){
return false; //ajax call will stop
}else{
return true; //ajax call
}
}

Creating dojo javascript function with callback

I have a dojo class like this.
var widget = declare("app.util",null, {
createSecuredLayers: function () {
$.ajax.get({
url: "/Api/GetLayer",
success: function (e) {
},
error: function () {
}
});
}
});
I want to use this object with callback parameters. I mean I want to pass success and error callbacks as parameter.
var util = new app.util();
util.createSecuredLayers({
success:function(){ },
error:function(){ }
});
createSecuredLayers: function(item) {
$.ajax.get({
url: "/Api/GetLayer",
success: item.successCallback,
error: item.errorCallback
});
}
When you call the method, don't forget to pass the response in the success callback.
util.createSecuredLayers({
successCallback: function(resp) {},
errorCallback: function(err) {}
});
You can do it like this:
var widget = declare("app.util",null, {
createSecuredLayers: function (args) {
$.ajax.get({
url: "/Api/GetLayer",
success: args.success,
error: args.error
});
}
});
var util = new app.util();
util.createSecuredLayers({
success:function(){ },
error:function(){ }
});
You should also consider using Dojo's deferred

use different parameter for a success callback

I'm working on someone else's code. I have this simple AJAX call in jQuery:
function getWSData (which, data, idVR)
{
if(which == 'verCandAll')
{
funcSuccess = verCandSuccess;
data = {'name' : 'val'};
}
else
{
funcSuccess = verElseSuccess;
data = {'name2' : 'val2'};
}
$.ajax({
type: 'POST',
url: wsURL,
data: data,
success: funcSuccess,
error:function ()
{
$("#msg").ajaxError(function()
{
popWaiting(false);
alert(verGenericCallError);
});
},
dataType: 'xml'
});
}
function verCandSuccess(xml){ ... }
function verElseSuccess(xml){ ... }
It's really simple. The only problem I have is the success callback. In case of verElseSuccess I would send a second parameter to that function, more precisely i would handle the idVR (an input parameter of getWSData). How can I accomplish this?
To achieve this, you can do:
...
if(which == 'verCandAll') {
...
}
else {
// create an anonymous function that calls verElseSuccess with a second argument
funcSuccess = function(xml) {
verElseSuccess(xml, idVR);
};
data = {'name2' : 'val2'};
}
...
Use Underscore.js partial function:
funcSuccess = _.partial(verElseSuccess, idVR);

JavaScript Scoping - Passing callback to already defined function

The title is a bit weird, don't quite know the best way to explain it in a sentence...
At present there is an object with 3 functions; func, funcSuccess, and funcFailure. func contains a jQuery ajax request, with this.funcSuccess as the success callback, and funcError as the error callback. func is passed a callback for any success values to be passed back to, however this callback needs to be executed in the funcSuccess code.
Here's the code:
var Obj =
{ func: function (callback) {
$.ajax(
{ type: 'POST'
, url: '/func'
, success: this.funcSuccess
, error: this.funcError
}
)
}
, funcSuccess: function (res) {
// THIS IS WHERE CALLBACK IS NEEDED
callback(res.thing)
}
, funcError: function (res) {
debug(res)
}
}
I'm wondering if there's a tidier way to do it rather than having:
var that = this
$.ajax(
{ type: 'POST'
, url: '/func'
, success: function (res) {
that.funcSuccess(res)
}
, error: this.funcError
}
)
Pretty sure I'm missing something obvious, just not quite with it today...
What about storing the callback explicitly in your object, so you don't have to worry about closure scopes:
var Obj =
{ func: function (callback) {
//this.callback = callback;
$.ajax(
{ type: 'POST'
, url: '/func'
, success: $.proxy(this.funcSuccess, this, callback)
, error: $.proxy(this.funcError, this)
}
)
}
, funcSuccess: function (callback, res) {
callback(res.thing)
}
, funcError: function (res) {
debug(res)
}
}
Edit: I forgot to bind the callbacks to this. In JQuery you can do it with $.proxy, see changes above.
Edit: A further tidy (jQuery 1.6 allows for this) with passing the callback as an argument to $.proxy, so no need to attach it to the current object.
You need to pass the callback into the funcSucess, else it won't have access to it. Here by using a closure:
var Obj = {
func: function (callback) {
return $.ajax({
type: 'POST',
url: '/func',
success: this.makeFuncSuccess(callback),
error: this.funcError
});
}, makeFuncSuccess(callback) {
return function funcSuccess (res) {
callback(res.thing);
};
},
funcError: function (res) {
debug(res)
}
};

jQuery's AJAX call to a javascript class method

I'm a newbee about jQuery's workflow and I would like to setup a javascript class that uses an internal method to make an AJAX request. When the request returns with success, the jQuery AJAX callback should invoke a method owned by the class itself. That's the code:
function IXClock()
{
this.m_intervalID = 0;
this.startClock = function ()
{
this.m_intervalID = setInterval(this.tictac, 500);
}
this.stopClock = function ()
{
clearInterval(this.m_intervalID);
}
this.setClockTime = function(p_strTime)
{
$('#clock').html(p_strTime);
}
this.tictac = function ()
{
$.ajax
({
type: 'POST',
url: '/rap/rapClock.php',
complete: function (data)
{
this.setClockTime(data);
}
});
}
}
The class represents a clock, with an internal method (tictac) that requests "what's the time" on the server side.
After the server says the time, the jQuery's AJAX method should invoke the setClockTime method of the IXClock class. The invoke method will update the #clock div item in the html page.
The problem is that the method this.setClockTime() results unknown and the javascript return the "this.setClockTime is not a function" error.
The question is: is there a way to invoka a class method from the jQuery's AJAX callback ?
I think that the problem is that the this in your callback function is different from the this referring to IXClock. Try:
var thisClass = this ;
this.tictac = function ()
{
$.ajax
({
type: 'POST',
url: '/rap/rapClock.php',
complete: function (data)
{
thisClass.setClockTime(data);
}
});
}
Test Case (added to site which already has jQuery loaded):
function uClass () {
this.testFunction = function(input) {
alert(input) ;
}
this.ajaxFunction = function() {
var myClass = this ;
$.ajax({
type: 'POST',
url: '/',
complete: function(data) {
alert(myClass.testFunction) ;
myClass.testFunction(data) ;
this.testFunction(data) ;
}
}) ;
}
}
var k = new uClass() ;
k.ajaxFunction() ;
It happens bacause your callback function leave in global context.
You can choose 2 ways
Use .bind function to bind context to callback function http://www.robertsosinski.com/2009/04/28/binding-scope-in-javascript/
jQuery's AJAX supports transfer some data to callback function. You can write smth like this:
:
this.tictac = function () { $.ajax ({ type: 'POST', context:this, url: '/rap/rapClock.php', complete: function (data) { this.setClockTime(data); } }); }
}
this does not refer to IXClock in your ajax callback. this allways points to the current scope (have a look at this document). You need to do something like this:
this.prototype.tictac = function ()
{
var self = this;
$.ajax
({
type: 'POST',
url: '/rap/rapClock.php',
complete: function (data)
{
self.setClockTime(data);
}
});
}
You can also use jQuery's .proxy()-function for this purpose:
this.prototype.tictac = function ()
{
$.ajax
({
type: 'POST',
url: '/rap/rapClock.php',
complete: $.proxy(function (data) {
this.setClockTime(data);
}, this)
});
}
The this in the result handler is not what you expect it is. (It is not the IXClock instance)
function IXClock()
{
this.m_intervalID = 0;
}
IXClock.prototype = {
startClock: function ()
{
this.m_intervalID = setInterval(this.tictac, 500);
},
stopClock: function ()
{
clearInterval(this.m_intervalID);
},
setClockTime: function(p_strTime)
{
$('#clock').html(p_strTime);
},
tictac: function ()
{
var that = this;
$.ajax({
type: 'POST',
url: '/rap/rapClock.php',
success: function (data) { // You want success here, not complete, IMO
that.setClockTime(data);
}
});
}
}
If you ask me, that ajax call is doing evil. It does not seem to send any data, nor modify any
state on the server, but is expecting/getting/using data from the php, yet is using the POST method.
Should've been
$.get('/rap/rapClock.php', function (data) {
that.setClockTime(data);
});
One simple solution is, to keep your callback function as self = this. This will support inheritance also.
class Record{
get_data(){
self = this;
$.ajax({
type : "GET",
url : "/get_url",
dataType : "json",
contentType: "application/json; charset=utf-8",
data : {},
success : function(data){
console.log(data);
self.load_table(data);
},
});
}
static load_table(data){
console.log(data);
}

Categories