pass this local js variable as an argument to a new function - javascript

I've read several posts on passing local function variables to new functions in javascript but am still having trouble in my own particular case.
I'm trying to pass the term argument given to data: function (term, page) to the generateUrl function below it. this.term = term and window.term = term (which I know is bad practice) aren't working. Should I try to declare a term variable outside of $(document).ready(function) or outside of the two inner functions, or or should I move the generateUrl definition inside of the $("#example").select2 function?
$(document).ready(function(){
$("#example").select2({
ajax: {
url: generateUrl(),
data: function (term, page) {
this.term = term; // i want to pass this local variable to generateUrl
}
}
});
function generateUrl(term) {
(function ($) {
var args = 'keywords=' + term;
return args;
}
(jQuery));
}
});

$(document).ready(function(){
$("#example").select2({
ajax: {
url: generateUrl(), /* You are calling generateUrl without parameter,
this will cause error
Did you actualy mean generateUrl(term) ? */
data: function (term, page) {
this.term = term; // i want to pass this local variable to generateUrl
generateUrl( this.term ); /* Is this what you want to do? */
}
}
});
function generateUrl(term) {
(function ($) {
var args = 'keywords=' + term;
return args;
}
(jQuery));
}
});

You should take a look into the select2 documentation, the example on section "Loading Remote Data" seems to be exactly what you're looking for. Based on that, I believe your code should be:
$(document).ready(function(){
$("#example").select2({
ajax: {
url: "", // replace that empty string with your ajax base url
// (without any parameters)
data: function (term, page) {
return { keywords : term };
}
}
});
});

Related

Accessing variable in .filter() scope with Mixpanel JQL

Working with Mixpanel & JQL I am trying to access a variable from the global scope in the .filter() function, so I could query only the desired records:
var selectedVal = 'foo';
MP.api.jql(function main() {
return People()
.filter(function(user) {
// Compare with 'selectedVal'
return user.properties["user-title"] == selectedVal;
})
;
}, selectedVal).done(function(results) {
// ...
});
Error:
{"request": "/api/2.0/jql/", "error": "Uncaught exception ReferenceError: selectedVal is not defined\n return user.properties[\"user-title\"] == selectedVal;\n ^\n\nStack trace:\nReferenceError: selectedVal is not defined\n at :6:70\n"}
If anyone could point me in the right direction, that would be great. Thank you
Edit:
At the moment I'm using a workaround by fetching all People entities and filtering afterwards. This is not optimal at all and thus am still looking for a way to get the result set on a property condition of the People entity.
Use bind. You can declare the function outside of MP.api.jql block and inside that jql function, you would pass in as a parameter, main.bind(null,whatever).
Looking into the unminified mixpanel-platform JS, the jql() function accepts a params object as second argument:
...
jql: function(script, params, settings) {
params = params || {};
settings = _.extend({type: 'POST'}, settings);
return this.query('/api/2.0/jql/', {
script: String(script),
params: JSON.stringify(params)
}, settings, function(data) {
return JSON.parse(data);
});
},
...
Solution:
var params = {
selectedVal : 'foo'
};
MP.api.jql(function main() {
return People()
.filter(function(user) {
return user.properties["user-title"] == params.selectedVal;
})
;
}, params).done(function(results) {
// ...
});

Sensible approach to callbacks on object prototype methods in JavaScript/jQuery?

Is what I've done below a sensible approach to allow callbacks to run on functions defined in an object's prototype, such that the scope is correct?
I've been wrestling with the correct way to set the value of this when an object's prototype method is the one to run in response to a callback which might originate from an AJAX request or from a click binding or whatever.
Here is a simplified annotated version:
// everything is inside an object which provides the namespace for the app
var namespace = {
// a fairly vanilla object creation routing, which uses the prototype
// approach for defining the functions on the object
newObj : function(params) {
var MyObj = function(params) {
this.property = params.property
};
MyObj.prototype = namespace.ObjPrototype;
return new MyObj(params);
},
// the prototype itself, which defines 2 related functions
ObjPrototype : {
// The first is called to do some form of asynchronous operation
// In this case it is an ajax call
doAsync: function (params) {
$.ajax({
type: "get",
url: params.url,
data: params.data,
dataType: params.datatype,
success: namespace.objClosure(this, "asyncSuccess", ["data"]),
});
// the final line above is the key here - it asks a function (below)
// for a closure around "this", which will in turn run the
// function "asyncSuccess" (defined next) with the argument "data"
},
// This is the actual callback that I want to run. But we can't
// pass this.asyncSuccess to the ajax function above, because the
// scope at execution time is all wrong
asyncSuccess : function(params) {
this.property = params.data;
},
},
// This is the bit I sort of invented, to help me around this problem.
// It returns a function which provides a closure around the object
// and when that returned function is run it inspects the requested
// arguments, and maps them to the values in the JS default
// "arguments" variable to build a parameters object which is then
// passed to the function on the object
objClosure : function(obj, fn, args) {
return function() {
if (args) {
var params = {};
for (var i = 0; i < args.length; i++) {
params[args[i]] = arguments[i];
}
obj[fn](params);
} else {
obj[fn]();
}
}
}
}
Now, obviously the actual target callback MyObj.asyncSuccess needs to know that it's going to get a params object, and what structure it will be, and that knowledge has to be shared by the invoking function MyObj.doAsync, but otherwise this seems to work well.
My question is - am I totally mad? Have I missed something obvious that would solve this problem for me in a simpler/less convoluted way? Am I just too far down the rabbit hole by this stage?
I've read around a lot of questions on SO and they have all addressed part of my question, but I don't seem to have got to the bottom of a generally accepted solution for this. I can't be the only person who's ever wanted to do this :)
Edit
I've accepted the answer below, but you need to read all the comments too for it to come together. Thanks folks for your help!
aren't you over complicating things? see if the below code will help you. i did not completely understand your intent but the below code should help you
function newObj(params) {
function asyncSuccess(params) {
this.property = params.data;
}
function objClosure(obj, fn, args) {
return function() {
if (args) {
var params = {};
for (var i = 0; i < args.length; i++) {
params[args[i]] = arguments[i];
}
obj[fn](params);
} else {
obj[fn]();
}
}
}
this.property = params.property
this.doAsync = function (params) {
console.log('reached async');
$.ajax({
type: "get",
url: params.url,
data: params.data,
dataType: params.datatype,
success: objClosure(this, "asyncSuccess", ["data"]),
});
}
}
var k = new newObj({'property':'xyz'});
k.doAsync();
After seeing the comment from "GameAlchemist" i looked into objClosure function i think we can further improvise by using below code: I am still not sure what the value of this.property or data is to give a proper solution hence just assuming few things
function newObj(params) {
function asyncSuccess(params) {
this.property = params ? params.data : null;
}
function objClosure(args) {
return function() {
if (args) {
var params = {};
for (var i = 0; i < args.length; i++) {
params[args[i]] = arguments[i];
}
asyncSuccess(params);
} else {
asyncSuccess();
}
}
}
this.property = params.property
this.doAsync = function (params) {
console.log('reached async');
$.ajax({
type: "get",
url: params.url,
data: params.data,
dataType: params.datatype,
success: objClosure(["data"]),
});
}
}
Few issues here:
if you are already passing params.data to data i.e. data:params.data how can you again assign the value this.property = params.data? Few things are confusing but i hope the above solution works : )

Better way of making javascript function a property

I was wondering if there was a way to use the get function in the url object below to generate property without wrapping it in an anonymous function.
It may be because I am just starting to dig into JavaScript after starting with jQuery, but something seems weird about wrapping a property in a anonymous function just to concatenate a string.
Current Object
var app = {
settings: {
webservice: 'http://abc.com/webservice/',
url: {
get: function (method) {
return app.settings.webservice + method;
},
caseSearch: function () {
return this.get('GetCases');
},
tipSearch: function () {
return this.get('GetTips');
},
propertySearch: function () {
return this.get('GetProperty');
}
}
}
};
Current
var url = app.settings.url.caseSearch();
Proposed
var url = app.settings.url.caseSearch;

Custom jQuery function - selector doesn't find element

I'm playing around with making a REST api and I'm working on some javascript functions.
The idea here is to run for example: $('#main').get('car/ford'); and the data returned will be added in the element provided.
Here is all the javascript:
$.fn.extend({
get: function (path) {
request(this, 'GET', path);
}
});
function request(element, type, path) {
var dees = $(element);
$.ajax({
type: type,
url: '/request/'+path,
success: function(data) {
console.log('Success');
a = $(element);
b = $('#fileList'); // this is a control
dees.html(data);
}
});
}
(function() {
console.log('running');
$('#fileList').get('car/ford');
})();
The problem I'm having is that when I run a.html(data);
Nothing will change. But if i run b.html(data);
Everything works like it should.
So there is a difference between those two selectors.
On a the element is not found a.length == 0
and on b the element is found b.length == 1
Why isn't the element found by the selector and how can I fix it?
The problem was solved by adding $ in front of the calling function.
From:
(function() {
console.log('running');
$('#fileList').get('car/ford');
})();
To:
$(function() {
console.log('running');
$('#fileList').get('car/ford');
});
You could try the following:
function request(element, type, path) {
var dees = $(element);
$.ajax({
type: type,
url: '/request/'+path,
success: function(data) {
console.log('Success');
dees.html(data);
}
});
}
in case the $(this) variable is conflicting with own $(this) variable of ajax() block.
Change element to $(element)
When request is call request(this, 'GET', path); this represents javascript object and it should be jQuery object. You need to pass jquery object or convert it to jquery object after being pass as I did.
$.fn.extend({
get: function (path) {
alert(this.tagName);
var objToPass = $(this);
request(objToPass, 'GET', path);
}
});
function request(javascriptObj, type, path) {
element = $(javascriptObj);
$.ajax({
type: type,
url: '/request/'+path,
success: function(data) {
console.log('Success');
a = $(element);
b = $('#fileList'); // this is a control
a.html(data);
}
});
}
Update
The call to get function should be instantiated on document.ready which could be done by simply adding $
Change
(function() {
console.log('running');
$('#fileList').get('car/ford');
})();
To
$(function() {
console.log('running');
$('#fileList').get('car/ford');
})();

Why has the author of this code used the .call method? Surely he could have just accessed the prototype?

Im looking through some code (unfortunatly the author isnt around anymore) and im wondering why he has used the .call method.
hmlPlaylist.prototype.loadVideos = function () {
var scope = this;
this.config.scriptUrl = '_HMLPlaylistAjax.aspx?' + Math.random();
jQuery.ajax({
type: 'GET',
url: this.config.scriptUrl,
success: function (d, t, x) {
scope.loadVideos_callback.call(scope, d);
},
error: function () {
}
});
};
hmlPlaylist.prototype.loadVideos_callback = function (data) {
var jsonData = '';
var jsonError = false;
try {
jsonData = eval("(" + data + ")");
} catch (jError) {
jsonError = true;
}
if (!jsonError) {
if (jsonData.playlists.length > 0) {
this.buildPlaylistList(jsonData.playlists);
}
if (jsonData.videos.length > 0) {
this.buildVideoList(jsonData.videos);
this.bindVideoNavs();
}
}
else {
// no json returned, don't do anything
}
};
Obviously he seems to have used it to pass a 'this' reference to the loadVideos_callback method but why? The 'loadVideos_callback' method is attached to the prototype of 'hmlplaylist' which is the 'class'. So if you access this inside the 'loadVideos_callback' method you get to the same thing dont you?
yes, I think you are right (I can't see the code in action). You still need the closure around scope, but in this case the use of call is not necessary.
To pull some of the comments into this answer, this is always the context on which the method was invoked. So if a new instance of htmlPlayList was created, and the method invoked on that instance, this would be a reference to that instance.

Categories