JavaScript - Chaining promises not running in order - javascript

I'm developing a small application where user can upload multiple file by a common input file field.
When an user clicks to the "Submit" button, I'm running this code:
function UploadFiles() {
var loadFiles = document.getElementById('selectedFile').files;
for (var i=0; i<=loadFiles.length;i++){
var fileOgg = loadFiles[i];
if (fileOgg!=undefined || fileOgg!=null){
new Promise(function (resolve, reject) { resolve (fileOgg); })
.then(UploadFilesStep)
.then(retrieveMetadata)
.then(changeMetadata)
.then(moveTo)
.then(showSuccess);
}
}
}
This is the UploadFilesStep detail:
var UploadFilesStep = function (fileOgg) {
return new Promise(function(resolve, reject) {
pnp.setup({ headers: { "Cache-Control": "no-cache", }, });
// This is a SharePoint PnP call to file upload
pnp.sp.web.getFolderByServerRelativeUrl("/sites/mysite/Config").files.add(fileOgg.name, fileOgg, true).then(function(result) {
console.log("FileUpload success");
resolve([result, fileOgg]);
});
})
}
The retrieveMetadata code:
var retrieveMetadata = function ([result, fileOgg]) {
return new Promise(function(resolve, reject) {
pnp.setup({ headers: { "Cache-Control": "no-cache", }, });
result.file.listItemAllFields.get().then(function(listItemAllFields) {
resolve([listItemAllFields, fileOgg]);
});
})
}
And this is the changeMetadata promise:
var changeMetadata = function ([listItemAllFields, fileOgg]) {
return new Promise(function(resolve, reject) {
pnp.setup({ headers: { "Cache-Control": "no-cache", }, });
pnp.sp.web.lists.getByTitle("Config").items.getById(listItemAllFields.Id).update({
Number: ""+number+"",
}).then(function(r){
console.log("Properties updated successfully! Go to MoveTo");
resolve(fileOgg);
});
})
}
And finally the MoveTo code:
var moveTo = function (fileOgg) {
return new Promise(function(resolve, reject) {
var nameFile = fileOgg.name;
var timestamp = + new Date();
var fileName = nameFile.substr(0, nameFile.lastIndexOf('.'));
var newFileName = fileName + "-" + timestamp;
var sourceFileUrl = _spPageContextInfo.webServerRelativeUrl+"/Config/"+nameFile+"";
var targetFileUrl = _spPageContextInfo.webServerRelativeUrl+"/Attachments/"+nameFile.replace(fileName, newFileName)+"";
var headers = headers || {};
var method = 'POST';
headers["Accept"] = "application/json;odata=verbose";
headers["X-RequestDigest"] = $("#__REQUESTDIGEST").val();
var endpointUrl = siteurl2 + "/_api/web/GetFileByServerRelativeUrl('" + sourceFileUrl + "')/MoveTo(newurl='" + targetFileUrl + "',flags=1)";
var payload;
$.ajax({
url: endpointUrl,
type: method,
contentType: "application/json;odata=verbose",
data: JSON.stringify(payload),
cache: false,
headers: headers,
async: false,
success: function (data) {
strResults += "";
counterUpload = counterUpload + 1;
resolve();
},
error: function (data) {
strResults += "Error " + JSON.stringify(data, null, 4);;
resolve();
}
});
});
}
From console of my browser I can see that first two promises (UploadFilesStep and retrieveMetadata) are running with the correct order.
Then, I can't see the changeMetadata log, but it seems going forward with the for loop in UploadFiles.
After a while I receive the response from changeMetadata and it often returns a 404 error ("Error making HttpClient request in queryable" linked to pnp js file).
What am i doing wrong?

Related

Javascript Fetch does not provide my content in Response message

I am struggling with the Response of the Javascript fetch() method. What is my objective: a) to send multiple lines to the backend to save those to a database and b) get a guid in return for further processing.
I succeed in objective a (save to database), but the return message fails to materialise. Response.ok is true, but no message is part of the return message.
What should I do to accomplish this?
My javascript is:
function saveAll(event) {
event.preventDefault();
var newDeelnemers = new Array();
var lijst = document.querySelectorAll('#tblDeelnemers tbody tr')
lijst.forEach(function (dnmr) {
var row = dnmr;
var deelnemer = {};
var nDnmr = row.children;
//deelnemer.Id = nDnmr[0].innerHTML;
deelnemer.FamilielidFirstName = nDnmr[0].innerHTML;
deelnemer.Achternaam = nDnmr[1].innerHTML;
deelnemer.DOB = nDnmr[2].innerHTML;
deelnemer.Programma = nDnmr[3].innerHTML;
deelnemer.EetMee = nDnmr[4].firstChild.checked;
deelnemer.Dieet = nDnmr[5].innerHTML;
deelnemer.Bedrag = nDnmr[6].innerHTML;
newDeelnemers.push(deelnemer);
});
fetch("/Familiedag/Registreer", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(newDeelnemers)
}).then(function (response) {
console.log('eerste keer: ' + response);
if (response.ok) {
alert('De registratie is gelukt');
//redirect("/Familiedag/RegistreerConfirm?")
}
});
}
The controller
[HttpPost]
public IActionResult Registreer([FromBody] List<FdDeelnemer> newDeelnemers)
{
if (newDeelnemers.Count == 0)
{
return null;
}
Guid registratieGuid = Guid.NewGuid();
foreach (var ndn in newDeelnemers)
{
FdDeelnemer VM = new FdDeelnemer();
VM.RegistratieGuid = registratieGuid;
VM.FamilielidFirstName = ndn.FamilielidFirstName;
VM.Achternaam = ndn.Achternaam;
VM.EetMee = ndn.EetMee;
VM.Dieet = ndn.Dieet;
VM.Programma = ndn.Programma;
VM.DOB = ndn.DOB;
VM.Bedrag = ndn.Bedrag;
VM.CreatedBy = User.Identity.Name;
VM.CreatedOn = DateTime.UtcNow;
_context.Add(VM);
}
Guid geregistreerdeDeelnemers = registratieGuid;
return Json(geregistreerdeDeelnemers);
}
add another .then that return the json
fetch("/echo/json/", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
"tes": "data"
})
}).then(function(response) {
return response.json();
}).then(function(json) {
console.log('eerste keer: ', json);
alert('De registratie is gelukt');
//redirect("/Familiedag/RegistreerConfirm?")
});
You can try to return it like that:
return Json(new { AnythingYouWant = geregistreerdeDeelnemers });

JavaScript Function ReEntrant in promise object

I would like to reentrant function in promise object.
this function contains Asynchronous processing.
however, this function dose NOT Work.
To be specified, DOES NOT fired ,next "then method".
the code is here
loopcount = 0;
getItemcount = 0;
global_ItemCol = [];
function GetItem_in_List_Over5000(parentSiteUrl, listGuid)
{
if (loopcount == 0) {
console.log("Enter FirstTime");
endPoint = parentSiteUrl + "/_api/Web/Lists(guid'" + listGuid + "')/Items?$top=3000&$select=Title,Id,ContentTypeId,HasUniqueRoleAssignments";
} else {
console.log("Eneter SecondTime");
}
return new Promise(function (resolve_GetItem_in_List5000, reject_GetItem_in_List5000) {
console.log("Eneter Inner Function");
$.ajax({
type: 'GET',
url: endPoint,
headers: { 'accept': 'application/json;odata=verbose', "X-RequestDigest": $("#__REQUESTDIGEST").val() },
success: function (data) {
console.log(data.d.__next);
if (data.d.__next) {
global_ItemCol = global_ItemCol.concat(data.d.results);
endPoint = data.d.__next;
loopcount++;
console.log("looopcount increment. " + global_ItemCol.length);
GetItem_in_List_Over5000(parentSiteUrl, listGuid);
} else {
global_ItemCol = global_ItemCol.concat(data.d.results);
var local_col = [];
local_col = local_col.concat(global_ItemCol);
loopcount = 0;
global_ItemCol.length = 0;
resolve_GetItem_in_List5000(local_col);
console.log("return call");
//return Promise.resolve().then(local_col);
resolve_GetItem_in_List5000(local_col);
}
},
error: function (error) {
OutputLog(error.responseJSON.error.message.value);
loopcount = 0;
reject_GetItem_in_List5000();
}
});
});
}
I called this function Added Array and Promise.All().
Thanks in advance.
You could try a recursive function. Store results in an array (not global but pass it to the recursive function). With every result set store the guid so you know what result set came from what guid (when requests start failing you know what you've done so far).
function GetItem_in_List_Over5000(parentSiteUrl, listGuid) {
const recur = (listGuid,results=[]) =>
$.ajax({
type: 'GET',
url: parentSiteUrl + "/_api/Web/Lists(guid'" + listGuid + "')/Items?$top=3000&$select=Title,Id,ContentTypeId,HasUniqueRoleAssignments",
headers: { 'accept': 'application/json;odata=verbose', "X-RequestDigest": $("#__REQUESTDIGEST").val() },
}).then(
function (data) {
console.log(data.d.__next);
if (data.d.__next) {
return recur(
data.d.__next,
results.concat([listGuid,data.d.results])
);
} else {
//add listGuid to result set so you know where it came from
return results.concat([listGuid,data.d.results]);
}
}
).fail(//newer jQuery can use .catch
err=>({type:"error",error:err,results:results})
);
return recur(listGuid)
}
GetItem_in_List_Over5000("url","guid")
.then(
results=>{
if((results&&results.type)===error){
console.log("something went wrong:",results.error);
console.log("have some results:",results.results);
}else{
console.log("got all results:",results);
}
}
)

Sharepoint AddIn upload .PDF via SP REST API

i have a function, which is uploading files to list item. Everything is working for .png, but when i'm trying to upload .pdf i have error net::ERR_CONNECTION_RESET
Screen of error object:
My code:
function uploadFile(listName, itemId, fileName, file) {
uploadFileSP(listName, itemId, fileName, file)
.then(function (files) {
//success
}, function (sender, args) {
alert('error: ' + args.get_message());
});
}
function getFileBuffer(file) {
var deferred = $.Deferred();
var reader = new FileReader();
reader.onload = function (e) {
deferred.resolve(e.target.result);
}
reader.onerror = function (e) {
deferred.reject(e.target.error);
}
reader.readAsArrayBuffer(file);
return deferred.promise();
}
function uploadFileSP(listName, id, fileName, file) {
var deferred = $.Deferred();
getFileBuffer(file)
.then(function (buffer) {
var bytes = new Uint8Array(buffer);
var content = new SP.Base64EncodedByteArray();
var binary = '';
for (var b = 0; b < bytes.length; b++) {
binary += String.fromCharCode(bytes[b]);
}
console.log(binary);
executor.executeAsync({
url: appweburl + "/_api/web/lists/getbytitle('" + listName + "')/items(" + id + ")/AttachmentFiles/add(FileName='" + file.name + "')",
method: "POST",
binaryStringRequestBody: true,
body: binary,
success: function (data) { alert('Pomyślnie dodano fakturę!'); window.location.replace("http://sharepoint-dev.ampliapps.com/FakturyBPNT-SharePoint-Hosted/Lists/Faktury/AllItems.aspx");},
error: function (err) { alert('Wystąpił błąd podczas wprowadzania faktury.'); console.log(err); },
state: "Update"
})
}, function (error) { deferred.reject(error); });
return deferred.promise();
}
As i said earlier, it works for .png for example.
This is what you need
function uploadDocument(contents, targetPath, successHandler, failedHandler) {
var fileName = getFilenameFromUrl(targetPath);
var fileNameEvidence = fileName;
var folderName = getPathFromUrl(targetPath);
var hostWebUrl = '';
var appWebUrl = '';
hostWebUrl = decodeURIComponent(getQueryStringParameter('SPHostUrl'));
appWebUrl = decodeURIComponent(getQueryStringParameter('SPAppWebUrl'));
$.getScript(hostWebUrl + "/_layouts/15/SP.RequestExecutor.js", function () {
console.log("into upload Api Document");
var byteArray = new Uint8Array(atob(contents).split("").map(function (c) {
return c.charCodeAt(0);
}));
var fileData = '';
for (var i = 0; i < byteArray.byteLength; i++) {
fileData += String.fromCharCode(byteArray[i]);
}
var reqDocExecutor = new SP.RequestExecutor(appWebUrl);
var _url = '';
var contentType = "application/pdf;odata=verbose";
var dotLocation = fileName.lastIndexOf('.');
var extensionFile = fileName.substr(dotLocation);
var info;
_url = String.format("{0}/_api/sp.appcontextsite(#target)/web/GetFolderByServerRelativeUrl('{1}')/files" + "/add(overwrite=true, url='{2}')?#target='{3}'", appWebUrl, folderName, fileName, hostWebUrl);
info = {
url: _url,
method: "POST",
headers: {
"Accept": "application/pdf; odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val()
},
contentType: contentType,
processData: false,
binaryStringRequestBody: true,
body: fileData,
success: function (x, y, z) {
successHandler();
},
error: function (x, y, z) {
console.log('failed to upload document');
failedHandler();
}
};
reqDocExecutor.executeAsync(info);
});
}

React-native NetInfo with promises

I have a modified code in react-native for fetching data with server, that works fine. I want to add NetInfo to always check before fetching if telephone has connection to internet. Is it posible inside promise? How to connect this async function to my code?
'use strict';
var MAX_WAITING_TIME = 30000
var processStatus = function (response) {
// status "0" to handle local files fetching (e.g. Cordova/Phonegap etc.)
if (response.status === 200 || response.status === 0 || response.status === 201 || response.status === 422 || response.status === 302 ) {
return Promise.resolve(response)
} else if(response.status === 413) {
return Promise.reject(alert(____mobile.connection_error.large_file))
} else {
//return Promise.reject(alert("Process status: "+JSON.stringify(response )))
return Promise.reject(alert(____mobile.connection_error.top));
console.log("Process status: "+JSON.stringify(response ));
}
};
var parseJson = function (response) {
return response.json();
};
var getWrappedPromise = function () {
var wrappedPromise = {},
promise = new Promise(function (resolve, reject) {
wrappedPromise.resolve = resolve;
wrappedPromise.reject = reject;
});
wrappedPromise.then = promise.then.bind(promise);
wrappedPromise.catch = promise.catch.bind(promise);
wrappedPromise.promise = promise;// e.g. if you want to provide somewhere only promise, without .resolve/.reject/.catch methods
return wrappedPromise;
};
/* #returns {wrapped Promise} with .resolve/.reject/.catch methods */
var getWrappedFetch = function () {
var wrappedPromise = getWrappedPromise();
var args = Array.prototype.slice.call(arguments);// arguments to Array
fetch.apply(null, args)// calling original fetch() method
.then(function (response) {
wrappedPromise.resolve(response);
}, function (error) {
// wrappedPromise.reject(alert("Fetch status: " + error));
wrappedPromise.reject(____mobile.connection_error.top);
console.log("Fetch status: " + error);
})
.catch(function (error) {
wrappedPromise.catch(error);
});
return wrappedPromise;
};
/**
* Fetch JSON by url
* #param { {
* url: {String},
* [cacheBusting]: {Boolean}
* } } params
* #returns {Promise}
*/
var postJSON = function (params) {
var headers1 = {}
if (params.json){
headers1 = {
'Accept': 'application/json',
'Content-Type': 'application/json'}
}
if (params.headersIn){
headers1 = params.headersIn
}
var methodTmp = 'POST'
if (params.methodIn) {
methodTmp = params.methodIn
}
console.log(methodTmp)
var wrappedFetch = getWrappedFetch(
params.cacheBusting ? params.url + '?' + new Date().getTime() : params.url,
{
method: methodTmp,//'POST',// optional, "GET" is default value
headers: headers1,
body: params.send_data
});
var timeoutId = setTimeout(function () {
wrappedFetch.reject(alert(____mobile.connection_error.timeout, ____mobile.connection_error.check_connection));// reject on timeout
}, MAX_WAITING_TIME);
return wrappedFetch.promise// getting clear promise from wrapped
.then(function (response) {
clearTimeout(timeoutId);
return response;
})
.then(processStatus)
.then(parseJson);
};
module.exports = postJSON;
What would be the bast way to implement: NetInfo.isConnected.fetch() so fetched would only worked when there is internet connection?
EDIT:
I want to use:
NetInfo.isConnected.fetch()
Yeah I have to rewrite this code, not to use getWrappedPromise and now I think is good time for it.
EDIT2: Ok I refactored this code fragment, hope its better. Any comments welcome. I tested and I'm not sure if I still need this NetInfo.isConnected.fetch(). Now there is no errors where there is no connection or am I missing something?
New code:
var processStatus = function (response) {
if (response == undefined) {
return null
}
// status "0" to handle local files fetching (e.g. Cordova/Phonegap etc.)
if (response.status === 200 || response.status === 0 || response.status === 201 || response.status === 422 || response.status === 302 ) {
return Promise.resolve(response)
} else if(response.status === 413) {
return Promise.reject(alert(____mobile.connection_error.large_file))
} else {
//return Promise.reject(alert("Process status: "+JSON.stringify(response )))
console.log("Process status: "+JSON.stringify(response ));
return Promise.reject(alert(____mobile.connection_error.top));
}
};
var parseJson = function (response) {
if (response == undefined) {
return null
}
return response.json();
};
var postJSON = function (params) {
var headers1 = {}
if (params.json){
headers1 = {
'Accept': 'application/json',
'Content-Type': 'application/json'}
}
if (params.headersIn){
headers1 = params.headersIn
}
var methodTmp = 'POST'
if (params.methodIn) {
methodTmp = params.methodIn
}
console.log(methodTmp)
var fetchPromise = fetch(params.cacheBusting ? params.url + '?' + new Date().getTime() : params.url,
{
method: methodTmp,//'POST',// optional, "GET" is default value
headers: headers1,
body: params.send_data
})// calling original fetch() method
.then(function (response) {
return response;
}, function (error) {
console.log("Fetch status: " + error);
return fetch
}).then(processStatus)
.then(parseJson);
// timeoutId = setTimeout(function () {
// wrappedFetch.reject(alert(____mobile.connection_error.timeout, ____mobile.connection_error.check_connection));// reject on timeout
// }, MAX_WAITING_TIME);
return fetchPromise
};

Ajax promise not working

I'm trying to use promise to return a comparison of current logged in user and a field from a list in SharePoint.
function compareCurrentUserWithListObject() {
var userProp = this._userProfileProperties;
var userName = userProp.get_userProfileProperties()['UserName'];
return this._list.filter(function (element, index, array) {
var promise = jQuery.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/GetUserById(" + element.user.get_lookupId() + ")",
type: "GET",
headers: { "Accept": "application/json;odata=verbose" }
});
promise.done(function(data) {
return (data.d.Email.indexOf(userName) > -1);
});
});
}
function init() {
var userArray = this.compareCurrentUserWithListObject();
userArray.done(function(res) {
if (res.length > 0) {
//Do some stuff after compare...
}
});
}
I'm not sure I'm using the .done correct here. Can someone help me?
EDIT:
Working code:
function compareCurrentUserWithListObject() {
var userProp = this._userProfileProperties;
var userName = userProp.get_userProfileProperties()['UserName'];
return this._list.filter(function (element, index, array) {
var promise = jQuery.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/GetUserById(" + element.user.get_lookupId() + ")",
type: "GET",
headers: { "Accept": "application/json;odata=verbose" }
});
promise.done(function(data) {
return (data.d.Email.indexOf(userName) > -1);
});
return promise;
});
}
function init() {
var userArray = this.compareCurrentUserWithListObject();
if (userArray.length > 0) {
//Do some stuff after compare...
}
}
you need to return the promise
function compareCurrentUserWithListObject() {
var userProp = this._userProfileProperties;
var userName = userProp.get_userProfileProperties()['UserName'];
return this._list.filter(function (element, index, array) {
var promise = jQuery.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/GetUserById(" + element.user.get_lookupId() + ")",
type: "GET",
headers: { "Accept": "application/json;odata=verbose" }
});
promise.done(function(data) {
return (data.d.Email.indexOf(userName) > -1);
});
// return promise here
return promise;
});
}
or this (which is cleaner IMO):
function compareCurrentUserWithListObject() {
var userProp = this._userProfileProperties;
var userName = userProp.get_userProfileProperties()['UserName'];
return jQuery.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/GetUserById(" + element.user.get_lookupId() + ")",
type: "GET",
headers: { "Accept": "application/json;odata=verbose" }
});
}
function init() {
this.compareCurrentUserWithListObject()
.done(function(data) {
var res = data.d.Email.indexOf(userName) > -1;
if (res.length > 0) {
//Do some stuff after compare...
}
});
}
it looks like you want to modify the response before using it in init. There is a way to do that but I'd do it inside the .done callback when using it.
I didn't test this code so there might be mistakes. But the general answer is: you need to return the promise.
The idiomatic way to do this using promises is to use Promise.all(). (I'll use Q promises as an example, but Promise.all is built into the JS6 promise API and several other promise libraries):
function getUserInfo(listItem) {
var promise = jQuery.ajax({
url: _spPageContextInfo.webAbsoluteUrl +
"/_api/web/GetUserById(" + listItem.user.get_lookupId() + ")",
type: "GET",
headers: { "Accept": "application/json;odata=verbose" }
});
return Q.Promise.when(promise);
}
function filterUsers(users) {
var userProp = this._userProfileProperties;
var userName = userProp.get_userProfileProperties()['UserName'];
return users.filter(function (user) {
return user.d.Email.indexOf(userName) > -1;
});
}
function init() {
Q.Promise.all(this._list.map(getUserInfo))
.then(filterUsers.bind(this))
.then(function (matchedUsers) {
// matchedUsers is an array of all the users you want.
// use it as needed
});
}

Categories