Javascript - Dependency injection and promises - javascript

I'm trying to pass an object around in JS (with some jQuery thrown in). :)
I want to call the FlappyBarHelper.getUserPropertyCount() method once the promise.success function has run. I've tried passing this.FlappyBarHelper to :
return $.ajax({
type: "GET",
url: 'get-the-score',
flappy: this.FlappyBarHelper,
});
But that still makes flappy undefined in promise.success
My full code is:
function Rating(FlappyBarHelper) {
this.FlappyBarHelper = FlappyBarHelper;
}
Rating.prototype.attachRaty = function(property_id)
{
var promise = this.getPropertyScoreAjax(property_id);
promise.success(function (data) {
$('#'+property_id).raty({
click: function (score, evt) {
$.ajax({
type: "GET",
url: '/set-the-score',
})
.done(function (msg) {
$('#extruderTop').openMbExtruder(true);
//**** FlappyBarHelper is undefined at this point ****///
FlappyBarHelper.getUserPropertyCount('.flap');
});
}
});
});
};
Rating.prototype.getPropertyScoreAjax = function(property_id)
{
return $.ajax({
type: "GET",
url: 'get-the-score',
});
}

Read from the documentation of ($.ajax](https://api.jquery.com/jQuery.ajax/)
The this reference within all callbacks is the object in the context option passed to $.ajax in the settings; if context is not specified, this is a reference to the Ajax settings themselves.
Therefore you should pass your variable along the multiple call you are doing:
Rating.prototype.attachRaty = function(property_id){
var promise = this.getPropertyScoreAjax(property_id);
// it's best to use done
promise.done(function (data) {
$('#'+property_id).raty({
// use proxy to keep context when the click will be received
click: $.proxy(function(score, evt) {
$.ajax({
type: "GET",
url: '/set-the-score',
// propagate your variable
FlappyBarHelper: this.FlappyBarHelper
}).done(function (msg) {
$('#extruderTop').openMbExtruder(true);
// here it should be defined
this.FlappyBarHelper.getUserPropertyCount('.flap');
});
}, this);
});
});
};
Rating.prototype.getPropertyScoreAjax = function(property_id) {
return $.ajax({
type: "GET",
url: 'get-the-score',
// propagate your variable
FlappyBarHelper: this.FlappyBarHelper
});
}
You can also consider making a closure variable:
Rating.prototype.attachRaty = function(property_id){
// here is the closure variable
var helper = this.FlappyBarHelper;
var promise = this.getPropertyScoreAjax(property_id);
// it's best to use done
promise.done(function (data) {
$('#'+property_id).raty({
click: function(score, evt) {
$.ajax({
type: "GET",
url: '/set-the-score'
}).done(function (msg) {
$('#extruderTop').openMbExtruder(true);
// you can still use the defined variable: power (and danger) of closures
helper.getUserPropertyCount('.flap');
});
}, this);
});
});
};
Rating.prototype.getPropertyScoreAjax = function(property_id) {
return $.ajax({
type: "GET",
url: 'get-the-score'
});
}

Related

Ajax Jquery run a function then with ajax inside and return success data

var datatobeuse = SearchTable("user_tbl", "first_name", "fname", "last_name", "lname");
I have this above code right after document ready.Then I have below code after document ready
function SearchTable(tablename, column1, label1, column2, label2) {
$.ajax({
type: 'POST',
url: '..user.php',
data: {
tablename: tablename,
column1: column1,
label1: label1,
column2: colum2,
label2: label2,
},
dataType: "json",
success: function (data) {
// console.log(JSON.stringify(data))
},
error: function (data) {
}
}).done(function (data) {
});
}
How can I use the data in success? I need to have return value so that I can use var datatobeuse which is right after document ready.
I tried solution from here
Like this one :
function isSession(selector) {
$.ajax({
type: "POST",
url: '/order.html',
data: ({ issession : 1, selector: selector }),
dataType: "html",
success: function(data) {
// Call this function on success
someFunction( data );
return data;
},
error: function() {
alert('Error occured');
}
});
}
function someFunction( data ) {
// Do something with your data
}
But it is not working
What you should do, is embrace the asynchronous character of javascript.
Asynchronous means it takes some time to execute the function, the rest of the javascript stuff will not wait for it. Ajax is an exellent example of this.
The solution is the callback. A callback is a function that will be called when the rest of the functionnality is ready.
I'll take your example to explain.
function isSession(selector, onReady) {
$.ajax({
type: "POST",
url: '/order.html',
data: ({ issession : 1, selector: selector }),
dataType: "html",
success: function(data) {
// all is finished. Now we can call the callback
if(typeof onReady == 'function') {
onReady(data);
}
},
error: function() {
}
});
}
function someFunction( data ) {
// Do something with your data
}
// now use them both
var selector = ".links";
isSession(selector, function(data) {
someFunction( data );
});
Reconsider why exactly you asked this question. You don't need a return value for your function.
This takes some different thinking. You wanted to know how to set the values to datatobeuse, like this:
var datatobeuse = somefunction();
// now datatobeuse is ready and we can use it.
displayOnScreen(datatobeuse);
Instead, think this way
var datatobeuse;
somefunction(function(data) {
datatobeuse = data;
displayOnScreen(datatobeuse);
})

How to set a conditional delay for making a request?

I have an array of symbols as shown below.
For each element of the array I am making an Ajax request.
var symbols = ["SSS", "SEE"]
$(document).ready(function () {
$.each(symbols, function (index, value) {
loadXMLDoc(value);
});
});
function loadXMLDoc(value) {
$.ajax({
type: 'POST',
url: 'https://ganaga/aaaa/sss',
success: function (data) {}
}
In the browser console, I see many XHR requests under pending state.
Is it possible to make the next Ajax request only when the response has been obtained for the previous array element?
var symbols = ["SSS", "SEE"]
$(document).ready(function () {
loadXMLDoc(symbols);
});
function loadXMLDoc(symbols) {
if(symbols[0]) {
$.ajax({
type: 'POST',
url: 'https://ganaga/aaaa/sss',
success: function(data){ loadXMLDoc(symbols.slice(1)) }
});
}
}
There is no value being used in loadXMLDoc in your question, I suppose you want:
url: 'https://ganaga/aaaa/'+ symbols[0],
Also, I would rename function to loadXMLDocs.
I would just use a little recursion:
var symbols = ["SSS", "SEE"]
$(document).ready(function () {
loadXMLDoc(0);
});
function loadXMLDoc(idx) {
value = symbols[idx];
if (value) {
$.ajax({
type: 'POST',
url: 'https://ganaga/aaaa/' + value,
success: function (data) {
//...
loadXMLDoc(idx+1);
}
});
}
}
Invoke the next AJAX call in the callback function.
function loadXMLDoc(n) {
var value = symbols[n];
$.ajax({
type: 'POST',
url: 'https://ganaga/aaaa/sss',
success: function (data) {
if (n < symbols.length-1) {
loadXMLDoc(n+1);
}
}
}
}
Start it with:
loadXMLDoc(0);

JQuery AJAX and OOP JS Scope Woes

So, I created an object which makes an AJAX call to populate its properties during the initialization phase. However, I am running into a very weird behaviour: I can print and see the property values fine within the $.ajax() scope, but any public method that returns the value of properties have a return value of "undefined".
Here's what the JS code looks like:
function MyFunction() {
this.myProperty;
this.init();
}
Myfunction.prototype.getPropertyValue = function () {
alert(this.myProperty); // returns 'undefined'
}
Myfunction.prototype.init = function () {
$.ajax({
type: 'get',
url: "getProperty.php",
dataType: "json",
success: function(response) {
this.myProperty = response[0].Property;
alert(this.myProperty) // returns 'Property Name'
}
});
}
My thinking is that within the $.ajax() scope, 'this' is actually referring to something else. So, my question is how do I make sure that 'this.myProperty' is set and doesn't lose its value once we get outside of the AJAX scope?
Any help is much appreciated.
Part of the reason why you're getting "undefined" because of the way you establish the value:
var MyFunction = function () {
this.myProperty;
alert(this.myProperty); // undefined!
this.init();
};
When you declare properties (or variables) without specifying a value, they default to "undefined". Instead:
var MyFunction = function () {
this.myProperty = false;
alert(this.myProperty); // false
this.init();
};
On to the ajax call. You are right that the scope of the callback is not the same as the object. this, in the ajax success function, refers to the jQuery-wrapped XHR object. When you call this.myProperty = response[0].Property, you are actually creating a new property on the ajax object and setting its value. To correct this, you can either use the context option of the jQuery ajax object, OR bind the callback function using the javascript bind method:
success: function(response) {
this.myProperty = response[0].Property;
}.bind(this)
... or:
$.ajax({
type: 'get',
url: "getProperty.php",
dataType: "json",
context: this,
success: function(response) {
this.myProperty = response[0].Property;
}
});
Try it here: http://jsfiddle.net/SnLmu/
Documentation
bind() on MDN - https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
jQuery.ajax() - http://api.jquery.com/jQuery.ajax/
Functions and Function Scope on MDN - https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope
Part of the problem is that the ajax is asynchronous so the properties may not be set when you try to access them (race condition). The other is the value of this inside of the ajax call is not Myfunction. You can fix by:
Myfunction.prototype.init = function () {
var that = this;
$.ajax({
type: 'get',
url: "getProperty.php",
dataType: "json",
success: function(response) {
that.myProperty = response[0].Property;
alert(that.myProperty) // returns 'Property Name'
}
});
}
or you can use the context setting in the ajax call. Per the site:
This object will be made the context of all Ajax-related callbacks. By
default, the context is an object that represents the ajax settings
used in the call ($.ajaxSettings merged with the settings passed to
$.ajax). For example, specifying a DOM element as the context will
make that the context for the complete callback of a request, like so:
Myfunction.prototype.init = function () {
var that = this;
$.ajax({
type: 'get',
url: "getProperty.php",
dataType: "json",
context: Myfunction,
success: function(response) {
this.myProperty = response[0].Property;
alert(this.myProperty) // returns 'Property Name'
}
});
}
var MyFunction = {
myProperty: null,
init: function() {
var self = this;
self.ajax(function(response) {
self.myProperty = response;
self.secondfunction(self.myProperty); //call next step only when ajax is complete
});
},
ajax: function(callback) {
$.ajax({
type: 'get',
url: "getProperty.php",
dataType: "json"
}).done(function(response) {
callback(response[0].Property);
});
},
secondfunction: function(prop) {
alert(prop);
}
}
$(function() {
MyFunction.init();
});

jQuery - get reference to this

function Request(params)
{
// Stuff stuff stuff
// And then
$.ajax(
{
type: 'GET',
url: 'someurl',
success: this.done
});
}
Request.prototype.done = function()
{
// "this" in this context will not refer to the Request instance.
// How to reach it?
}
You could capture "this" first:
function Request(params)
{
// Stuff stuff stuff
// And then
var $this = this;
$.ajax(
{
type: 'GET',
url: 'someurl',
success: function() { $this.done(); }
});
}
Apparently you can add the "context" parameter to the ajax request, like so:
$.ajax(
{
type: 'GET',
url: 'someurl',
success: this.done,
context: this
});
this is not reffering to the same thing!!!
try following:
function Request(params)
{
var that = this;
....
Request.prototype.done = function()
{
that...

javascript undefined

Why cant I access the render function when ajax returns successfully? maybe im going crazy but i've done this before.
Its telling me that this.render is not a function?
DataItem.prototype = {
display: function () {
$('body').append(this.name + ": " + this.getData(this.rootData, this.subData) + "<br />");
},
getData: function (rootData, subData) {
$.ajax({
type: "GET",
url: "json/data.js",
data: "",
dataType: "json",
success: function (json){
this.render(json);
}
});
},
render: function (json) {
var res = [];
for(var i=0, t; t=json.log.entries[i]; i++) {
var p = t.request.url;
if (p!=undefined) res.push(p);
}
return res.length;
}
};
The scope has changed when you try to call this.render(). I believe this contains the ajax request object instead of the DataItem object.
A simple solution is doing like this:
getData: function (rootData, subData) {
var self = this;
$.ajax({
type: "GET",
url: "json/data.js",
data: "",
dataType: "json",
success: function (json){
self.render(json);
}
});
},
Edit: I was wrong, inside the success function the this variable contains the options for the ajax request, however my solution is still correct. See more in the jQuery documentation (http://docs.jquery.com/Ajax/jQuery.ajax#options)
Just to add to #adamse answer. If you want to externalize your success function instead of using an anonymous function you could use the following to pass additional parameters:
function handleSuccess(json) {
this.self.render(json);
}
$(function() {
$.ajax({
type: "GET",
url: "json/data.js",
data: "",
dataType: "json",
// pass an additional parameter to the success callback
self: this,
success: handleSuccess
});
});
since the following code works (i.e "abcd" is printed), I am not sure what is the problem you are facing unless you would share more code.
<script>
DataItem = function(){};
DataItem.prototype = {
display: function () {
return 'a';
},
getData: function () {
document.write(this.render());
return this;
},
render: function () { return "abcd"; }
};
di = new DataItem();
di.getData();
</script>

Categories

Resources