Trying to solve problem were my object has old snapshot of itself and refuses to update itself when I replace it with new data using AJAX.
var user, status;
function getData(){
var userData = getUserData(),
orderStatus = getOrderStatus(),
allDone = $.when(userData, orderStatus);
allDone.then(function(data, data2){
status = parseInt(data2[0]);
user = JSON.parse(data[0]);
console.log("User", user);
});
}
function getUserData() {
return $.ajax({
type: "POST",
url: functionsPath,
data: {
action: 'getUserData'
}
});
}
function getOrderStatus() {
return $.ajax({
type: "POST",
url: functionsPath,
data: {
action: 'getOrderStatus'
}
})
}
//onclick event
function verify(){
console.log(user);
}
Here is screenshot of the problem: This first one is from console. I call this inside getData() function. Take a closer look into user.content.page4
Next image is taken from network tab. As you can see data is different when it not. There are "symbols" with values. Why are these two different?
This is problem when I try to call user within verify() since it has the old snapshot of itself and doesn't return my symbols etc. It really feels like a console bug. Symbols are listed in database.
EDIT
I think I got more closer to the problem. Result loses its "Symbol-1", "Symbol-2" and so on immediately when I parse it. So when I parse user.content page4 loses Symbol properties.
Before parsing I have it, but soon as I parse it I lose every symbol properties and their values.
Related
I make a $.post call by sending array of objects (selected values from a checkbox tree) to my API every time the mouse leave the div where checkbox tree is located. The issue is that the user by moving randomly the mouse could leave and enter the div houndreds of times so that will cause useless $.post submission without getting new data as the sent content hasn't changed.
Actually here is how the code looks like right now:
$("div.sidebar-wrapper")
.mouseleave(function () {
postPareto();
});
function postPareto() {
$.ajax({
type: "POST",
data: JSON.stringify(config_Array()),
url: "api/prodotti/pareto/",
contentType: "application/json",
success: function (dati) {
tablePareto(dati);
}
});
}
So my question is, is there a way to prevent the $.post to being submissed if the content hasn't changed or should i just find another approach to submiss the checkbox selection (as it's a checkbox tree i chose to submit data on mouseleave so the user will have some time to decide what to check)?
In this case I would do the following (simple solution):
$("div.sidebar-wrapper")
.mouseleave(function () {
postPareto();
});
// Save reference to previous value
let prevValue = null;
function postPareto() {
let data = JSON.stringify(config_Array());
// If it is the same value we can return and not perform POST
if (data === prevValue){
return;
} else {
// Assign new value to prevValue
prevValue = data;
}
$.ajax({
type: "POST",
data: JSON.stringify(config_Array()),
url: "api/prodotti/pareto/",
contentType: "application/json",
success: function (dati) {
tablePareto(dati);
}
});
}
It might be a good idea to look into rxjs, it's quite cool and powerful for reactive sites. For example in rxjs you could do:
const input = document.querySelector('div.sidebar-wrapper');
const observable = fromEvent(input, 'mouseleave');
observable
.map((event: any) => config_Array()),
.distinctUntilChanged() // Returns an Observable that emits all items emitted by the source Observable that are distinct by comparison from the previous item.
.subscribe((resp) => {
// This will only be called if value changes
console.log(resp); // resp will be the result from `config_Array()`
});
You can check this article, which explains this a bit more in depth
I have been writing many web apps with php & mysql & jquery & bootstrap and now it's time address this problem. How to write shorter ajax queries(posting) ?
If I want to write code that works and takes care of many problems, it's too long for every ajax call.
Is there a better way or some library / wrapper that makes the code SHORTER and FASTER to write, but does atleast all these stuff
I looked popular axios, but it seems even worse
//JUST an example code, too complicated
var $btnStatusElem = $("#passwordreset").button('loading');
$.ajax({
type: "POST",
cache: false,
url: "pwreset.php",
data: postdata
success: function(data) {
$btnStatusElem.button('reset');
try {
var datajson = JSON.parse(data);
}
catch (e) {
alert('Unexpected server error');
return false;
};
if (datajson['success'] == true) {
//do the OK stuff
} else {
//show the error code, and stuff
return false;
}
},//success
error: function(msg) {
alert('ERROR');
$('#passwordreset_result').html(msg);
}
});
For my code, ajax query, i want it to do these steps:
1. Disable the submit button while posting (re-enable also after 15 seconds and not just leave it disabled until page refresh)
2. It sends json, expects json to return
3. If server has some error, it DOES NOT return json but error. Then the code will halt all js execution if i dont use try...catch. This is pain to write each time
4. If server returns validation error or some other expected error, i have to detect this and show to the user
5. If all ok, do the stuff
As with any refactoring, identify and isolate the repetitive code and pass in the unique bits. In this case, for example, you could isolate the ajax call and json parsing into a function and pass in the url, data, etc.
That function could return a promise that resolves/rejects as appropriate.
Given the doRequest function below (pseudocode, untested and would probably need a bit of tweaking for real-world use), you could then use it all over the place with fewer keystrokes:
doRequest('pwreset.php', postdata, button)
.then(result => {
// do something with the result
})
.catch(error => {
// deal with the error
});
or
try {
const result = await doRequest('pwreset.php', postdata);
// do something with result
}
catch (e) {
// handle error
}
All of the boilerplate stuff is isolated in doRequest.
async function doRequest(url, data, button, type = "POST") {
return new Promise((fulfill, reject) => {
$.ajax({
type,
url,
data,
cache: false,
success: function(data) {
$btnStatusElem.button('reset');
try {
const datajson = JSON.parse(data);
} catch (e) {
return reject(e);
};
return datajson['success'] == true ?
fulfill(datajson) :
reject(datajson);
}, //success
error: function(msg) {
return reject(msg);
}
});
})
}
As #mister-jojo says, you might also want to consider using the [fetch api] instead of jQuery, but the same principle applies.
I'm trying to send a "large" table in OfficeJS:
functionfile.html loaded from manifest route
<script>
(function (){
"use strict";
Office.initialize = function (reason) {
$(document).ready(function() {
$("#send-data-button").click(send_data);
});
};
function send_data() {
return Excel.run( function(context) {
var data = context.workbook.worksheets.getItem("SheetName")
.getRange("A1:K3673").load("values");
return context.sync().then( function() {
// 2d table is correctly seen
// $("body").append(data.values);
// Just gets lost in ajax call
$.ajax({
type: "GET",
url: mysite,
data: {"accessData": data.values},
}).done( function(success) {
$("body").append("All Done");
}).fail( function(error) {
$("body").append("Error == " + JSON.stringify(error));
});
return context.sync();
});
});
}
})();
</script>
<div> <button id="send-data-button"> Send </button></div>
However i'm not sure how to send this, on the backside I have a flask server catching the request and was hoping I could just use pandas.read_json but no matter how I try to send this i'm getting different errors. Here's the printout of flask.request when data.values[0][0]:
CombinedMultiDict([ImmutableMultiDict([('update_date', '43191'), ('accessData', 'Channel')]), ImmutableMultiDict([])])
And when I try data.values[0] I get a list of values, which is what i'd expect
CombinedMultiDict([ImmutableMultiDict([('update_date', '43191'), ('accessData[]', 'Channel'), ... <All my column headers>, ImmutableMultiDict([])])
But when I try to send the 2D array with just data.values I get an error message in ajax.fail:
Error == {"readyState":0,"status":0,"statusText":"error"}
I also tried JSON.stringify(data.values) and got the same error message:
Error == {"readyState":0,"status":0,"statusText":"error"}
I even tried to take each column and convert them to some kind of list as nested keys inside accessData but I was getting the same error message. Any help would be greatly appreciated.
Ideally, you should isolate the getting-data-from-Excel part from your ajax call part. Right now, the two are intertwined, which makes it both harder to help debug, and just conceptually less clean.
For the Excel part, you should be able to do:
function getExcelData(){
return Excel.run( function(context) {
var data = context.workbook.worksheets.getItem("SheetName")
.getRange("A1:K3673").load("values");
return context.sync()
.then(function() {
return data.values;
});
})
}
This will free you up to then do:
getExcelData().then(function(values) {
$.ajax(...)
});
Note that range.values returns just a regular 2D array, nothing special. So you can try out your ajax call independently of the Excel call (which is yet another reason to separate those out)
I have the following function to check a users session to see if they're staff or not. Now, I know there are better ways to do this, but I'm trying to make a simple application that's tied with a forum software.
function isStaff(callback) {
$.ajax({
url: url
}).done(function(data) {
var session = $.parseJSON(data);
if (session.is_staff === 1) {
callback(true);
} else {
callback(false);
}
});
}
Let's say I'm using this function in, like so, when compiling a "post" (Handlebars).
function compilePost(post) {
var source = $('#feed-item-template').html();
var template = Handlebars.compile(source);
var context = {
id: post.id,
content: post.text,
author: post.author,
date: $.timeago(post.date),
staff: function() {
isStaff(function(response) {
return response;
});
}
}
var html= template(context);
return html;
}
Problem here, is that the request to check if a user is staff doesn't complete the request until after the function is ran.
I know with Promises is an alternative to async: false, where request is made and the response comes back before the function finishes.
But I have no idea how I can convert this into a promise. I've tried to learn it but I'm stuck at the concept. Can someone explain this to me? Thanks.
First, let's simplify the compilePost function. This function should know how to compile a post in a synchronous manner. Let's change the isStaff fetching to a simple argument.
function compilePost(post, isStaff) {
var source = $('#feed-item-template').html();
var template = Handlebars.compile(source);
var context = {
id: post.id,
content: post.text,
author: post.author,
date: $.timeago(post.date),
staff: isStaff
}
var html= template(context);
return html;
}
Now, let's create a new method, with a single purpose - checking if a user is member of the staff:
function checkForStaffMemebership() {
return new Promise(function (resolve, reject) {
$.ajax({
url: url,
success: function (data) {
var session = $.parseJSON(data);
if (session.is_staff === 1) {
resolve(true);
} else {
resolve(false);
}
}
});
});
}
This function wraps your original ajax call to the server with a promise, whenever the $.ajax call gets a response from the server, the promise will resolve with the answer whether the user is a staff member or not.
Now, we can write another function to orchestrate the process:
function compilePostAsync(post) {
return checkForStaffMemebership()
.then(function (isStaff) {
return compilePost(post, isStaff);
});
}
compilePostAsync finds out whether the user is a staff member or not. Then, it's compiling the post.
Please notice that compilePostAsync returns a promise, and thus if you used to have something like:
element.innerHTML = compilePost(post);
Now, you should change it to something like:
compilePostAsync(post).then(function (compiledPost) {
element.innerHTML = compiledPost;
});
Some notes:
This is only an example, it surely misses some things (proper error handling for example)
The isStaff and checkForStaffMemebership (original and new) do not get any argument, I guess you'd figure out how to pass the userId or any other data you might need
Read about promises, it's a useful tool to have, there is a lot of data about it on the web, for example: MDN.
As per the documentation you dont need to wrap the ajax with a promise which already implements promise. Instead chain the response as explained below.
The jqXHR objects returned by $.ajax() as of jQuery 1.5 implement the Promise interface, giving them all the properties, methods, and behavior of a Promise (see Deferred object for more information)
You can do something like below by chaining the response:
function isStaff(url, post) {
return $.ajax({
url: url,
dataType:"json"
}).then(function(resp){
//resp = $.parseJSON(resp); /*You dont require this if you have respose as JSON object. Just Specify it in 'dataType'*/
var source = $('#feed-item-template').html();
var template = Handlebars.compile(source);
var context = {
id: post.id,
content: post.text,
author: post.author,
date: $.timeago(post.date),
staff: resp.is_staff === 1 ? true : false
};
return template(context);
});
}
isStaff(url, post).done(function(template){
/*Your compiled template code is available here*/
}).fail(function(jqXHR, textStatus, errorThrown){
console.log("Error:"+textStatus);
});
Note: Be sure to implement error callbacks also. Because you may never know what
went wrong :)
Simple explanation about promise with $.defer:
For understanding i have created the Fiddle similar to your requirement.
Explanation:
Basically Promise is been introduced to attain synchronous execution of asynchronous JS code.
What do you mean by Async or Asynchronous code?
The code that is executed may return a value at any given point of time which is not immediate. Famous example to support this statement would be jquery ajax.
Why is it required?
Promise implementations helps a developer to implement a synchronous code block which depends on asynchronous code block for response,. like in ajax call when i make a request to server asking for a data string, i need to wait till the server responds back to me with a response data string which my synchronous code uses it to manipulate it , do some logic and update the UI.
Follow this link where the author has explained with detailed examples.
PS: Jquery $.defer implements or wraps promise in quite a different way. Both are used for the same purpose.
let basedataset = {}
let ajaxbase = {};
//setting api Urls
apiinterface();
function apiinterface() {
ajaxbase.createuser = '/api/createuser'
}
//setting up payload for post method
basedataset.email = profile.getEmail()
basedataset.username = profile.getGivenName()
//setting up url for api
ajaxbase.url = ajaxbase.createuser
ajaxbase.payload = basedataset;
//reusable promise based approach
basepostmethod(ajaxbase).then(function(data) {
console.log('common data', data);
}).catch(function(reason) {
console.log('reason for rejection', reason)
});
//modular ajax (Post/GET) snippets
function basepostmethod(ajaxbase) {
return new Promise(function(resolve, reject) {
$.ajax({
url: ajaxbase.url,
method: 'post',
dataType: 'json',
data: ajaxbase.payload,
success: function(data) {
resolve(data);
},
error: function(xhr) {
reject(xhr)
}
});
});
}
A solution using async await in js would be like this:
async function getMyAjaxCall() {
const someVariableName = await ajaxCallFunction();
}
function getMyAjaxCall() {
return $.ajax({
type: 'POST',
url: `someURL`,
headers: {
'Accept':'application/json',
},
success: function(response) {
// in case you need something else done.
}
});
}
Function 1: Get JSON Data & Store
I am creating a script where an array of twitch channels will go through the JSON function loop to be processed and then stored using "localStorage.setItem" as temporary storage. I'm saving them in name,viewer and url.
Function 2: Sort Data
Stored data can later be used to display the information without having to use function 1 again.
Problem
The sortdata function keeps on firing before function 1 is complete. Resorting in error because the data is undefined. This error popped before the console displays all the information stored from function 1.
My code:
$(window).load(function(){
$.when(getData()).promise().done(function(){
getStoredObj();
});
});
function getData(){
var streamArray=[];
jQuery.each (channels, function (i, channel) {
channelId = channel.id;
channelUrl = channel.url;
var promise = $.ajax({
dataType: "jsonp",
url: twitchApi + channelId,
success: 1,
}).done(function ( data ) {
if (data.stream == null) {
} else {
var displayName = data.stream.channel.display_name;
var viewerCount = data.stream.viewers;
streamArray.push({name: displayName, views: viewerCount, url: channelUrl});
localStorage.setItem("storedStreamArray", JSON.stringify(streamArray));
console.log(JSON.stringify(streamArray));
}
});
});
}
function getStoredObj () {
var retrievedObject = localStorage.getItem('storedStreamArray');
var parsedObject = JSON.parse(retrievedObject);
<sorting codes here>
}
Some help here really appreciated. :)
You're calling $.when with the result of getData, but getData doesn't return anything, let alone a deferred that when can use. As a result, there's nothing to wait for and your done callback calls getStoredObj immediately.
In getData, you need to collect all the deferreds returned by your ajax calls and pass them back to the caller. That would look like:
function getData(){
return jQuery.map (channels, function (i, channel) {
return $.ajax(...).done(function ( data ) {
// Do work
});
});
}
Each iteration returns its ajax deferred, which are aggregated by map and returned to the caller. Then you can run when on the result and wait for loading to finish before you sort anything.