How retrieve results after asynchronous function? - javascript

I've read posts on asynchronous calls and callbacks but i did not find my answer.
i've a simple dropdown button on my boostrap page, who let users change values.
So when button is clicked, i call an ajax function to do the job, and we must wait for result of the action.
After that, i want to change dropdown button value and give the result of the operation to the user.
So this is my callback function with ajax (which works great) :
function changePermissions(user, role, callBack){
var ret = false;
$.ajax({
url: "lib/edit_permissions.php",
data: {'user': user, 'role': role},
type: 'post',
dataType: 'json',
success: function(data) {
if($.isPlainObject(data) && data.state === 200){
ret = true;
}
else {
console.log(data.message);
}
return callBack( ret );
},
error: function (xhr, ajaxOptions, thrownError) {
console.log("thrown error");
return callBack( ret );
}
});
}
If i try to retrieve the result outside the function, the value is undefined, i understand that it is an asynchronous problem:
$(".dropdown-menu li a").click(function(){
var newrole = $(this).text();
var result=false;
result = changePermissions(user, newrole, function(ret) {
return ret;
});
}
if (result){
$(this).parents(".dropdown").find('.btn').html(newrole + ' <span class="caret"></span>');
console.log("permissions successfully updated.");
}
else {
console.log("Error to update permissions");
}
If i try to retrieve the result inside the function, the result is OK. But i can't update my button text value, '$this' seems to be undefined:
$(".dropdown-menu li a").click(function(){
var newrole = $(this).text();
var user = $(this).parents(".dropdown").closest('td').prev('td').text();
changePermissions(user, newrole, function(ret) {
if (ret){
$(this).parents(".dropdown").find('.btn').html(newrole + ' <span class="caret"></span>');
console.log("user permissions successfully updated.");
}
else{
console.log("error to update");
}
});
});
How can i do that ?

That is normal because, this inside callback doesn't refers to DOM object or target of the event. It overrides. To use it, you need to create a local copy of that and to use that copy inside callback. Here is code.
$(".dropdown-menu li a").click(function(){
var newrole = $(this).text();
var user = $(this).parents(".dropdown").closest('td').prev('td').text();
//make copy of this
var self = this;
changePermissions(user, newrole, function(ret) {
if (ret){
//use that copy
$(self).parents(".dropdown").find('.btn').html(newrole + ' <span class="caret"></span>');
console.log("user permissions successfully updated.");
}
else{
console.log("error to update");
}
});
});

Related

search in JSON with AJAX

I have to search inside a json file with a value from my input, everything is fine capturing the value and the event, but when I iterate something unexpected happens for me.
How can I select an object based on this search?.
the problem is that when doing .each it goes through all the records, even those not found.
$( document ).on('turbolinks:load', common_events)
function common_events(){
$('.rut-input').on('change', function(event){
$rut = $(this).val();
var searchField = $rut;
var expression = new RegExp(searchField, "i");
event.preventDefault();
$.ajax({
type: "GET",
url: '/companies/',
dataType: 'JSON',
success: function(companies){
$.each(companies, function(i, company) {
if (company.rut.search(expression) > -1){
console.log(company.id);
$('.name-input').empty();
$('.name-input').val(company.name);
$('.name-input').addClass('disabled-input');
$('.form-group').removeClass('hide');
console.log(company.address);
if (company.address == null ){
$('.address-input').removeClass('disabled-input');
};
}
else {
console.log('no encuentra');
console.log(company);
$('.form-group').removeClass('hide');
$('.form-control').removeClass('disabled-input');
};
});
},
error: function(companies){
console.log('A ocurrido un error')
},
});
});
}
when executing the event, both the if and else are executed at the same time.
Seems like you don't really want to iterate the companies array with each. You want to find a matching company, and then do something with that record.
success: function(companies){
const company = companies.find(c => c.rut.search(expression) > -1);
if (company) {
console.log(company.id);
$('.name-input').empty();
$('.name-input').val(company.name);
$('.name-input').addClass('disabled-input');
$('.form-group').removeClass('hide');
console.log(company.address);
if (company.address == null ){
$('.address-input').removeClass('disabled-input');
}
} else {
console.log('no encuentra');
console.log(company);
$('.form-group').removeClass('hide');
$('.form-control').removeClass('disabled-input');
}
},

return when duplicate html table

I have a function that can remove the duplicate in my html table.
var seen = {};
$('#tblSerial tr').each(function() {
var txt = $(this).text();
txt = txt.trim();
if (seen[txt]) {
isExist = true;
alertify.error("This serial is already on contract.");
$(this).remove();
return; //this should return
} else
seen[txt] = true;
});
But the problem now is that, below that code there's an AJAX call which always call even I return in the duplicate error.
$.ajax({
type: "GET",
url: siteURL + '#Url.Action("valcontract", "contract")',
data: data_model,
success: function (response) {
if (response.success) {
} else {
$('#serial').val("");
alertify
.error(response.responseText);
return;
}
},
error: function (response) {
alertify
.error(response.responseText);
return;
}
});
I want to block the AJAX call if there's a duplicate in my serial table.

jQuery AJAX function call

I have a problem with jQuery calling an AJAX function, basically everytime a user changes a select box, I want it to call the getSubCategories function, but for some reason, nothing is happening. Any ideas?
If I load the page and add console.log inside the getSubCategories function it logs it, should that even be happening?
function getSubCategories() {
var id = $("#category").prop('selectedIndex');
var selectedCategory = $("#category").val();
//should change this into a response from AJAX and grab the slug from there, this is fine for now.
var slugOfCategory = convertToSlug(selectedCategory);
id++;
console.log('here');
$.ajax({
method: 'GET', // Type of response and matches what we said in the route
url: '/product/get_subcategories', // This is the url we gave in the route
data: {
'id': id
}, // a JSON object to send back
success: function(response) { // What to do if we succeed
$("#sub_category option").remove(); //Remove all the subcategory options
$.each(response, function() {
$("#sub_category").append('<option value="' + this.body + '">' + this.body + '</option>'); //add the sub categories to the options
});
$("#category_slug").attr('value', slugOfCategory);
},
error: function(jqXHR, textStatus, errorThrown) { // What to do if we fail
console.log(JSON.stringify(jqXHR));
console.log("AJAX error: " + textStatus + ' : ' + errorThrown);
}
});
}
function getCategories() {
var id = $("#type").prop('selectedIndex');
var selectedType = $("#type").val();
//should change this into a response from AJAX and grab the slug from there, this is fine for now.
var slugOfType = convertToSlug(selectedType);
console.log(slugOfType);
//add one to the ID because indexes dont start at 0 as the id on the model
id++;
$.ajax({
method: 'GET', // Type of response and matches what we said in the route
url: '/product/get_categories', // This is the url we gave in the route
data: {
'id': id
}, // a JSON object to send back
success: function(response) { // What to do if we succeed
$("#category option").remove(); //Remove all the subcategory options
$.each(response, function() {
$("#category").append('<option value="' + this.name + '">' + this.name + '</option>'); //add the sub categories to the options
});
$("#type_slug").attr('value', slugOfType);
},
error: function(jqXHR, textStatus, errorThrown) { // What to do if we fail
console.log(JSON.stringify(jqXHR));
console.log("AJAX error: " + textStatus + ' : ' + errorThrown);
}
});
}
function convertToSlug(Text) {
return Text
.toLowerCase()
.replace(/ /g, '_')
.replace(/[^\w-]+/g, '');
}
$(document).ready(function() {
var firstCatgegory = $("#category").val();
var slugOfFirstCategory = convertToSlug(firstCatgegory);
$("#category_slug").attr('value', slugOfFirstCategory);
var firstType = $("#type").val();
var slugOfFirstType = convertToSlug(firstType);
$("#type_slug").attr('value', slugOfFirstType);
$("#type").change(getCategories());
$("#category").change(getSubCategories());
});
Thanks for any help. (Sorry the code is a little messy, i've just been trying to get it to work so far)
This is due to the fact that the ajax call you are trying to make is asynchronous. When you call getSubCategories() it returns undefined which is why your code is not working.
To make this work you need to put your code within the success callback function instead.
<script>
function getSubCategories()
{
var id= $("#category").prop('selectedIndex');
$.ajax({
method: 'GET',
url: '/product/get_subcategories',
data: {'id' : id},
success: function(response){
// DO SOMETHING HERE
},
error: function(jqXHR, textStatus, errorThrown) { }
});
}
$( document ).ready(function() {
// This is also wrong. Currently you're passing
// whatever is returned from getSubCategories
// (which is undefined) as the callback function
// that the "change" event will call. This instead
// should be the reference to the function. Which
// in this case is getSubCategories
$("#category").change(getSubCategories);
});
Please put getCategories() and getSubCategories() Methods inside Change function like this.Sorry for not code formatting.
<script>
$(document).ready(function(){
$("#category").change(function(){
getSubCategories();
});
$("#type").change(function(){
getCategories();
});
});
</script>

Using Jquery/SetTimeout to Update Div - Update Not Working

What I am Trying to Do:
I am trying to use settimeout to loop/run after a function is called to automatically update/refresh a div.
What Isn't Working:
To be clear settimeout is working, but the div is not automatically refreshing/updating when I enter new test data into the db. In other words, If I refresh the page, I see the new test data, but not if I let the update function run.
Code:
function update(a) {
$.ajax({ //create an ajax request to load_page.php
type: "GET",
url: "core/engine.php",
data: "q=data&account="+a,
dataType: "html", //expect html to be returned
success: function(response){
if(response=="nologin") {
alert("Sorry, but either your account is not activated or your login is incorrect!");
} else {
console.log("Queried Database...");
var j = $.parseJSON(response);
$.each(j, function (k, v) {
$("#login-box").hide();
//$("#trades").html(' ');
localStorage.setItem("wings_lastsignal", v.candel);
var lastsignal = localStorage.getItem("wings_lastsignal");
console.log(v.candel);
if(lastsignal == v.candel) {
console.log("No New Signals");
localStorage.getItem("wings_currentsignals");
if(v.signal == 'Buy') {
console.log("Current Buy Sent...");
$("#trades").append('<span id="'+v.candel+'" class="tradesignal"><span class="signalarrowup"></span>'+v.time+'<span style="color:#2DC14E;"> '+v.signal+'</span>   <button class="tsym" id="sym_'+v.epoch+'" onClick="var a = this.innerHTML; tsclick(a);" value="'+v.symbol+'">'+v.symbol+'</button>  '+v.price+'  '+v.timeframe+'</span>');
} else {
console.log("Current Sell Sent...");
$("#trades").append('<span id="'+v.candel+'" class="tradesignal"><span class="signalarrowdown"></span>'+v.time+'<span style="color:#fb5350;"> '+v.signal+'</span>   <button class="tsym" id="sym_'+v.epoch+'">'+v.symbol+'</button>  '+v.price+'  '+v.timeframe+'</span>');
}
} else {
playChing();
console.log("New Signal");
if(v.signal == 'Buy') {
console.log("Buy Sent...");
$("#trades").append('<span id="'+v.candel+'" class="tradesignal"><span class="signalarrowup"></span>'+v.time+'<span style="color:#2DC14E;"> '+v.signal+'</span>   <button class="tsym" id="sym_'+v.epoch+'" onClick="var a = this.innerHTML; tsclick(a);" value="'+v.symbol+'">'+v.symbol+'</button>  '+v.price+'  '+v.timeframe+'</span>');
} else {
console.log("Sell Sent...");
$("#trades").append('<span id="'+v.candel+'" class="tradesignal"><span class="signalarrowdown"></span>'+v.time+'<span style="color:#fb5350;"> '+v.signal+'</span>   <button class="tsym" id="sym_'+v.epoch+'">'+v.symbol+'</button>  '+v.price+'  '+v.timeframe+'</span>');
}
}
});
}
//alert(response);
//console.log(response);
}
}).then(function() { // on completion, restart
var a = localStorage.getItem("wingsaccnum");
//setTimeout(update, 10000);
setTimeout(function(){ update(a) }, 20000); // function refers to itself
console.log("Timeout");
});
}
This function is called when I a button is pressed, using this Jquery snippet:
$( "#rbuttonon" ).click(function() {
var acc = localStorage.getItem("wingsaccnum");
//refresh_box();
update(acc);
console.log('Interval set');
});
Other Notes:
To be clear, I don't mind if there is a way to always make sure this div is updated every xx amount of time, without the need to press any buttons. I believe the problem is in my code's logic, but I would greatly appreciate some assistance!

Updating an element via ajax: shall I use global variable to keep element's id or it is a bad habit?

On a page I have a list of dates which I want to edit via AJAX.
Example:
<li>January 2015<a data-update_url="/frame_date/22/update/" class="update" id="update_framedate_22" href="javascript:void(0)">Edit</a>
When the user clicks on the Edit link, I catch element id and the edit link.
Than AJAX requests the update form from the server. And now I have to place the form instead of the element with the mentioned id.
In other words, in frame_date_update_show_get I need element's id. In the example below, I keep it in the global variable date_id. But inside me there is a protest: I was always taught that global variables is a bad practice. But in this case I don't know how to get along without the global variable date_id.
Could you give me some piece of advice: is my code acceptable or there is a better way to cope with the problem.
function frame_date_update_show_get(data){
$("#" + date_id).replaceWith(data);
}
function frame_date_update_get_data(){
date_id = this.getAttribute('id')
var cuaghtUrl = this.getAttribute('data-update_url');
$.ajax({
method: 'get',
url: cuaghtUrl,
success: frame_date_update_show_get,
error: fail
});
}
var date_id = ""
Use an anonymous function as success callback function and then call frame_date_update_show_get with an additional date_id parameter:
function frame_date_update_show_get(data, date_id) {
$("#" + date_id).replaceWith(data);
}
function frame_date_update_get_data() {
var date_id = this.getAttribute('id')
var cuaghtUrl = this.getAttribute('data-update_url');
$.ajax({
method: 'get',
url: cuaghtUrl,
success: function(data) {
frame_date_update_show_get(data, date_id);
},
error: fail
});
}
I would use contenteditable combined with AJAX this way:
function dateChange(options){
switch( options.action ) {
case 'update':
if( options.id && options.text && options.updateUrl ) {
$.ajax({
method: 'post',
url: options.updateUrl,
data: {
id: options.id,
html: options.text
},
success: function(response) {
options.element.html( response );
options.element.removeClass('editing');
},
error: function(err) {
console.log( 'request failed: ' + err.text );
}
});
};
break;
default:
console.log( 'action invalid' );
return false;
break;
};
};
var editTimeout = null;
$('li[data-update-url]').on('input', function(e) {
var thisText = $(this);
thisText.addClass('editing');
clearTimeout( editTimeout );
editTimeout = setTimeout(function() {
var updateUrl = thisText.data('updateUrl');
var id = thisText.data('id');
dateChange({
'action': 'update',
'element': thisText,
'id': id,
'updateUrl': updateUrl,
'text': thisText.html()
});
}, 1000);
});
.editing {
color: orange;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li data-update-url="/echo/html/" data-id="update_framedate_22" contenteditable>January 2015</li>
</ul>
Check how it works on JSFiddle.
This code would be easy to expand for other actions you may need, as delete, add.

Categories

Resources