Passing "this" inside a promise? - javascript

I am trying to learn about promises.
My URL will contain three ID parameters, e.g.
#org=123&num=145&denom=467
and I want to use these to select the values of three select elements on my page (each one with an Ajax source), e.g.
<select id="org"><option selected val="123">Birmingham University</option></select>
<select id="num"><option selected val="145">Maths</option></select>
<select id="denom"><option selected val="467">English</option></select>
The complicated bit is that I need to do an Ajax request for each ID, so that I can pre-fill the name part of the option as well as the ID.
Then once all three requests are complete, I want to continue to render the rest of the page.
I've got most of the way there, but I'm stuck on how to get the value of this inside the getNumerators function. Can anyone help?
setUp: function() {
// use hash to set this.globalOptions
var _this = this;
_this.setFormValues().then(function() {
this.setUpRestOfForm ...
};
},
setFormValues: function() {
return _this.getOrgs()
.then(_this.getNumerators)
.then(_this.getDenominators)
.then(function() {
return true;
}
});
},
getOrgs: function() {
return $.ajax({
type: 'GET',
url:'/api/orgs/?q=' + this.globalOptions.orgId,
dataType: 'json'
});
},
getNumerators: function(orgIds) {
// FAILS: Cannot set property 'orgIds' of undefined
this.globalOptions.orgIds = orgIds;
var url = '/api/subjects/?q=' + this.globalOptions.numId;
return $.ajax({
type: 'GET',
url: url,
dataType: 'json'
});
}
Any other advice on the way I'm doing this would also be gratefully received.

You can use Funtion.bind()/$.proxy() to pass a custom execution context
setFormValues: function() {
return _this.getOrgs()
.then(_this.getNumerators.bind(_this)) //using bind() - supported in IE9+
.then($.proxy(_this.getDenominators, _this)) //using $.proxy()
.then(function() {
return true;
}
});
}
or you can pass a custom context using context option in ajax
getOrgs: function() {
return $.ajax({
type: 'GET',
url:'/api/orgs/?q=' + this.globalOptions.orgId,
dataType: 'json',
context: this
});
},

Related

AJAX data is sent empty to PHP Function

I need to send the id of an element and a value (1,2,3) through ajax to a PHP document that checks if the data is empty (which is always). The two values I'm trying to send are correctly logged on the console though.
$(document).ready(function() {
$('.status-menu-option-1').click(function(){
changeLabelStatus(1);
});
$('.status-menu-option-2').click(function(){
changeLabelStatus(2);
});
$('.status-menu-option-3').click(function(){
changeLabelStatus(3);
});
function changeLabelStatus(status){
var parent = $(event.target).parent().parent().parent().attr('id');
console.log(status);
console.log(parent);
$.ajax({
url: 'team/canva_change_label',
type: "GET",
data: {
status : status,
row : parent
},
success: function(msg) {
if(msg.error) {
alert(msg.error_msg);
return;
}
}
});
}
}
I know I'm doing something wrong but I can't point what.
$(document).ready(function() {
$('.status-menu-option-1').click(function(e){
changeLabelStatus(e.target, 1);
});
$('.status-menu-option-2').click(function(e){
changeLabelStatus(e.target, 2);
});
$('.status-menu-option-3').click(function(e){
changeLabelStatus(e.target, 3);
});
function changeLabelStatus(element, status){
var parent = $(element).parent().parent().parent().attr('id');
console.log(status);
console.log(parent);
$.ajax({
url: 'team/canva_change_label',
type: "GET",
data: {
status : status,
row : parent
},
success: function(msg) {
if(msg.error) {
alert(msg.error_msg);
return;
}
}
});
}
}
You need to pass in the element that the event resulted from, rather than relying on the event being a global variable, which is not standard behavior for all browsers.
Also, you should be able to use a form of closest(selector) instead of all those chained parent calls, but without seeing the markup I can't suggest a proper selector.

How to put ajax request inside function and call it when necessary?

I have an ajax request:
$.ajax({
type: 'POST',
url: '/get-result.php',
dataType: 'json',
data: 'pid=' + $(this).attr("id"),
success: function(response) {
$(".reviewee-fname").append(response['fname']);
$(".reviewee-lname").append(response['lname']);
} }); };
I want to be able to put this inside a function that waits for me to trigger it with a return call. I am not exactly sure how to word it, I am new to javascript and jquery. But basically, I want to trigger this ajax call with various different button clicks and instead of having to put the ajax call inside every button click event, I want to put it in a stand alone function so if I ever update it later I dont have to change it 5 times.
Heres an example of a click event Id like to call the ajax request function with. Thanks!
$(function() {
$(".task-listing").click(function() {
//Call Ajax function here.
});
});
Callbacks are well-suited for this scenario. You can encapsulate your ajax call in a callback function.
function apiCall() {
$.ajax({
type: 'POST',
url: '/get-result.php',
dataType: 'json',
data: 'pid=' + $(this).attr("id"),
success: function(response) {
$(".reviewee-fname").append(response['fname']);
$(".reviewee-lname").append(response['lname']);
} }); };
}
You can now hook apiCall()method as a callback to button click.
$(function() {
$(".task-listing").click(apiCall);
});
By doing this you will able to achieve this.
I want to put it in a stand alone function so if I ever update it later I dont have to change it 5 times.
EDIT:
Note:
This is lead to start, you can alter this according to your requirement.
Is this not working for you? ↓↓
$(function() {
$(".task-listing").click(function() {
let pid = $(this).attr("id"); //get any other value which you want to pass in function, say url
someFunction(pid); // pass any other parameters, eg- someFunction(pid, url)
});
});
function someFunction(pid){ // someFunction(pid, url)
$.ajax({
type: 'POST',
url: '/get-result.php', // url: url
dataType: 'json',
data: 'pid=' + pid,
success: function(response) {
$(".reviewee-fname").append(response['fname']);
$(".reviewee-lname").append(response['lname']);
}
});
}

Determine ajax call finished to run another ajax call

In my project I have some select option group which load ajax data depending on previous value. Now I am having problem when I am trying to copy them to another select option group.
here is the scenario
parmanet address Present Address
Division Division
District District
Upzilla Upzilla
Union Union
All of them are select field and after select each field next select option loaded by ajax. I put a checkbox and when user click the checkbox, parmanent address data should copy to present address with all the ajax call.
Now The problem is, the jquery "val" function not working because it runs before the data loaded from ajax. If I put delay to 100 ms, it working, but It's not a proper way. Is there any better way to solve this problem??
This is my code when i change division to load ajax data to division, and other option is same as like this.
$('#divisions').change(function() {
$("#villtable").hide();
$("#villaddform").hide();
$.ajax({
type: 'post',
url: 'GetDistricts',
data: {
get_option:this.value
},
success: function(response) {
document.getElementById("districts").innerHTML=response;
}
});
});
And this is what i tried to copy data to present address group...
$.when( $('.division-prese').val(divi).trigger('change').delay( 100 ) ).then(function() {
$.when( $('.district-prese').val(dist).trigger('change').delay( 100 ) ).then(function() {
$.when( $('.upazilla-prese').val(upaz).trigger('change').delay( 100 ) ).then(function() {
$('.union-prese').val(unio).trigger('change');
});
});
});
i also tried 'done', but still not working.
General idea of extracting the logic and using it in two places, one of which performing the promise chaining.
function loadDistricts ($divisions) {
return $.ajax({
type: 'post',
url: 'GetDistricts',
data: {
get_option: $divisions.val()
},
success: function(response) {
$('#districts').html(response);
}
});
}
//... other methods
var $divisions = $('#divisions');
var $districts = $('#districts');
var $upazillas = $('#upazillas');
$divisions.change(function() {
$("#villtable").hide();
$("#villaddform").hide();
loadDistricts($divisions);
});
//... other change methods
$('.division-prese').val(divi);
loadDistricts($divisions).then(function(){
$('.district-prese').val(dist);
loadUpazillas($upazillas).then(function(){
$('.upazilla-prese').val(upaz);
//call next thing
});
});
try adding return before your call
$('#divisions').change(function() {
$("#villtable").hide();
$("#villaddform").hide();
return $.ajax({
type: 'post',
url: 'GetDistricts',
data: {
get_option:this.value
},
success: function(response) {
document.getElementById("districts").innerHTML=response;
}
});
});

JS AJAX typeahead result ordering / race condition

I'm encountering an issue with AJAX typeahead / live-update as-you-type views which are returning results out of order. Does anyone have any experience with methods of dealing with this?
The problem:
Type in a query, such as "search term".
Even with some debouncing, it's likely to fire off a few AJAX calls as you type, say "sea", and "search term".
The search result set for sea is larger than the one for search term, and so its AJAX request actually completes after the newer query.
The resulting problem: You type in search term, but the correct results blip across the screen for a second only to be replaced by the results for sea.
Bare-bones jQuery pseudocode:
$('body').on('keyup', '#searchBox', function(){
query = $("#searchBox").val();
$.ajax({
type: 'GET',
url: '/endpoint.php?query=' + query,
success: function (response) {
// Update view here
$("#view").html(response.text);
}
});
});
Angular pseudocode:
// HTML
<input ng-keyup = "search()" ng-model="searchBox" placeholder = "Search">
{{results}}
// JS
$scope.search = function(){
$http({
method: 'GET',
url: '/endpoint.php?query=' + $scope.searchBox
}).then(function successCallback(response) {
$scope.results = response.data;
}, function errorCallback(response) {
console.log(response);
});
}
Top stop the race condition you can keep a reference to the last AJAX request you made and then abort() it when a new key is pressed. It would also be worthwhile putting a delay before making the request so that you don't send a request for every key pressed, but for when typing ends. Try this:
var previousRequest, previousTimer;
$('body').on('keyup', '#searchBox', function() {
previousRequest && previousRequest.abort();
clearTimeout(previousTimer);
previousTimer = setTimeout(function() {
previousRequest = $.ajax({
type: 'GET',
url: '/endpoint.php',
data: {
query: $("#searchBox").val()
},
success: function (response) {
// Update view here
$("#view").html(response.text);
}
});
}, 200);
});
200ms between keystrokes is plenty, but you can shorten if you want to increase the responsiveness of the requests.

Setting data-content and displaying popover

I'm trying to get data from a resource with jquery's ajax and then I try to use this data to populate a bootstrap popover, like this:
$('.myclass').popover({"trigger": "manual", "html":"true"});
$('.myclass').click(get_data_for_popover_and_display);
and the function for retrieving data is:
get_data_for_popover_and_display = function() {
var _data = $(this).attr('alt');
$.ajax({
type: 'GET',
url: '/myresource',
data: _data,
dataType: 'html',
success: function(data) {
$(this).attr('data-content', data);
$(this).popover('show');
}
});
}
What is happening is that the popover is NOT showing when I click, but if I hover the element later it will display the popover, but without the content (the data-content attribute). If I put an alert() inside the success callback it will display returned data.
Any idea why is happening this? Thanks!
In your success callback, this is no longer bound to the same value as in the rest of get_data_for_popover_and_display().
Don't worry! The this keyword is hairy; misinterpreting its value is a common mistake in JavaScript.
You can solve this by keeping a reference to this by assigning it to a variable:
get_data_for_popover_and_display = function() {
var el = $(this);
var _data = el.attr('alt');
$.ajax({
type: 'GET',
url: '/myresource',
data: _data,
dataType: 'html',
success: function(data) {
el.attr('data-content', data);
el.popover('show');
}
});
}
Alternatively you could write var that = this; and use $(that) everywhere. More solutions and background here.
In addition to the answer above, don't forget that according to $.ajax() documentation you can use the context parameter to achieve the same result without the extra variable declaration as such:
get_data_for_popover_and_display = function() {
$.ajax({
type: 'GET',
url: '/myresource',
data: $(this).attr('alt'),
dataType: 'html',
context: this,
success: function(data) {
$(this).attr('data-content', data);
$(this).popover('show');
}
});
}

Categories

Resources