I have resource that has following fields:
description, picture
Is it possible to send that resource to URL as multipart/form, and if so, how?
I've tried putting:
app.factory('resource_name', ['$resource', function($resource) {
return $resource('<url> ',
{
<params_for_url>
},
save: {
method: "POST",
headers: {
"Content-Type": "multipart/form-data;"
}
},
but this doesn't get to the server as form-data. It goes like JSON with header just set:
{
description: "gtrdgf",
picture: {
lastModifiedDate:2013-11-26T20:42:13.000Z,
name: "suggested_pokes.png"
size: 32995
type: "image/png"
webkitRelativePath: ""
}
Did anyone met this requirement before? If this is possible at all...
Thanks!
I found solution for this one. You have to use FormData to submit it. You can use it as interceptor. I used it like this (this is my save method of ngResource)
save: {
method: 'POST',
transformRequest: formDataObject,
headers: {'Content-Type':undefined, enctype:'multipart/form-data'}
},
and here is transformer:
function formDataObject (data) {
var fd = new FormData();
angular.forEach(data, function(value, key) {
fd.append(key, value);
});
return fd;
}
Related
I have created a utility function which is supposed to be common for all the api requests in node.js express app.
function axiosCall(method, endpoint, body) {
let requestConfig = {
url: encodeURI(`${endpoint.host}:${endpoint.port}${endpoint.path}`),
method: method, //can be POST, GET, etc
proxy: false,
data: body,
headers: {
"x-access-token": token,
"X-Correlation-ID": correlationId,
"Content-Type": "application/json"
},
}
axios.request(requestConfig).then(response => {
return response.data;
}).catch((errorRes) => {
throw {
error: errorRes.message, status: errorRes?.response?.status || 500,
responseContent: errorRes?.response?.data || "Server Error"
};
})
}
it works fine for JSON responses, but does not give proper result for files, such as pdf.
the response which i got for a pdf file was like
{
"status": 200,
"statusText": "OK",
"headers": {
"server": "nginx/1.16.1",
"date": "Fri, 02 Sep 2022 07:39:44 GMT",
"content-type": "application/pdf",
"content-length": "47658",
"connection": "close",
},
"config": {...},
"request": {...},
"data": "%PDF-1.4\r\n%����\r\n1 0 obj\r\n<<\r\n/Type /Catalog\r\n/Pages 2 0 R\r\n/AcroForm 3 0 R\r\n>>\r\nendobj\r\n4 0 obj\r\n<<\r\n/�����M��0\u0010��B�C������\u0016�#?���`��\u0003�N���\u0012���~�L��\u001e| O2�y3���;�fP�o�\u0013\u000e�Ҹ�c��}����E�VuS\r�W��Vv�h�>=�\u0001oGwi�j�⯰�\u000f����=�,��5��]��g{�ŧ{���\rݠ\u0012\u0000U�%��Vv��\rUL5�c\u001d���1\u000f\u0015�'�\u001f\u001d*M��jk컲B_�+N�U�$\u0019\u0004�-L\"t��\u0001�s���Z��\t�*MA����\u0005a���h�4O�\u0006�)H�9\bm�j\u0001BkX-Ah-+��i�wm#h\u0017�� �KV{\u0010�\r�\u0003\b햔I#hw��a�嶍\u0006�=��#Xp^��c\u0016ܣ1 ,4+N�Xp^!#a���X�\u0005�c8Ob�Il薑:IC�᭟oJ�\u001e�3����އy�\t�A\u001aG�q(C�X��7��\u0000�t��\r\nendstream\r\nendobj\r\n26 0 obj\r\n<<\r\n/Type /Font\r\n/Subtype /CIDFontType2\r\n/BaseFont /GBMOJY+SymbolMT\r\n/CIDToGIDMap /Identity\r\n/DW 1000\r\n/FontDescriptor 31 0 R\r\n/CIDSystemInfo <<\r\n/Registry (Adobe)\r\n/Ordering (Identity)\r\n/Supplement 0\r\n>>\r\n\r\n/W [120 [459]]\r\n>>\r\nendobj\r\n27 0 obj\r\n<<\r\n/Filter /FlateDecode\r\n/Length 225\r\n>>\r\nstream\r\nx^m�ϊ�0\u0010��\u001c� �^�P\n�\"����\u0000i2-��$L�C�~�T\u0014\u0016\u000f\u0019\u0018~�\r_F��sE6��a�k\f�Z2��\u001bY#4�Y\u0012�\u001d\u0018�\u0003,]��W>\u00133]OC����AQ���t\b<��ø\u0006��\r17~��0CM`\u001f��+��W�la��B��6\u000f��6l�$�֥�n��J�K���S[~ݤ�\u0003�5�]}ր����TV���ճG��Di���xQa� ?�K��\r�����ސmT�}q��Ԙ��\u0019�֕�\u0018c�\u0001�\u001a|/}!��qfJў<y��\u0007c��y\t\u001c\b ks]v]Fmz弦o\u0019����u�v_�|�[_F>�G�w�m:n��.�m$�ZҨ�F-i�\u0014〯�o\u001c�\u00120fJ\u0012`��Oz��{rP�v\u0011\u0004�}�����\u001d�\u0016�L\\�\u000b�\u001d�n�C]�I�����MZ�~۷��Iu��\u0014�6o�?�����W��ꡦ#?ZXG��wL�\u0007���G\t���3�Y���DFl�����R� 34\r\n>>\r\n\r\nstartxref\r\n46886\r\n%%EOF\r\n"
}
I am unable to convert this response.data to pdf file.
Then i read about setting responseType: "arraybuffer", which gave the buffer[] and I can use it in code to generate the file. but on setting the responseType, the error was also of buffer type instead of json. which again required further processing to convert it to json format.
so, is there a way to get pdf file from axios, by converting the response.data, which I received with default responseType.
or can we set responseType dynamically after getting response from the server, as i get the content-type in headers. so as to make a utility function which can work with all kinds of responses.
As I didn't get a proper resolution i handled it manually by passing a flag to the axios utility function.
const customObjectify = (data) => {
try {
if(typeof data === "string"){
JSON.parse(data);
}
return data;
} catch (error) {
return data;
}
}
main block is below
//adding a default value false to parameter, so i don't need to change at all function calls.
function axiosCall(method, endpoint, body, isFileInResponse= false) {
let requestConfig = {
url: encodeURI(`${endpoint.host}:${endpoint.port}${endpoint.path}`),
method: method, //can be POST, GET, etc
proxy: false,
data: body,
headers: {
"x-access-token": token,
"X-Correlation-ID": correlationId,
"Content-Type": "application/json"
},
}
if(isFileInResponse){
requestConfig.responseType = "arraybuffer";
}
axios.request(requestConfig).then(response => {
return response.data;
}).catch((errorRes) => {
try {
let responseContent;
if(isFileInResponse) {
// arraybuffer error needs to be converted to json
responseContent = customObjectify(errorRes.response.data.toString());
} else {
responseContent = errorRes.response.data;
}
throw ({ error: errorRes.message, status: errorRes?.response?.status || 500, responseContent});
} catch (error) {
throw ({ error: errorRes.message, status: errorRes?.response?.status || 500, responseContent: "Server Error" });
}
throw {
error: errorRes.message, status: errorRes?.response?.status || 500,
responseContent: errorRes?.response?.data || "Server Error"
};
})
}
As mentioned in this question (https://stackoverflow.com/a/53230807/19179818) you could put code in your .then() to create an anchor tag on your page and click it automatically to download the file, and delete the tag afterwards. (posted as awnser instead of comment because of not enough reputation)
I use this call: https://{site_url}/_api/web/GetFolderByServerRelativeUrl('/ Folder Name')/Files/add(url ='a.txt', overwrite = true).The file is inserted correctly but I don't know what to add so that I can fill the rest of the columns of the library of documents.But it can be done in the same call, it doesn't matter. But I need to modify the value in a record of a document library
Warrior,
Do you want to update values of other columns after uploading a file to a library? If so, you may hava a look below demo:
function getItem(file) {
var call = jQuery.ajax({
url: file.ListItemAllFields.__deferred.uri,
type: "GET",
dataType: "json",
headers: {
Accept: "application/json;odata=verbose"
}
});
return call;
}
function updateItemFields(item) {
var now = new Date();
var call = jQuery.ajax({
url: _spPageContextInfo.webAbsoluteUrl +
"/_api/Web/Lists/getByTitle('Documents')/Items(" +
item.Id + ")",
type: "POST",
data: JSON.stringify({
"__metadata": { type: "SP.Data.DocumentsItem" },
CoordinatorId: _spPageContextInfo.userId,
Year: now.getFullYear()
}),
headers: {
Accept: "application/json;odata=verbose",
"Content-Type": "application/json;odata=verbose",
"X-RequestDigest": jQuery("#__REQUESTDIGEST").val(),
"IF-MATCH": item.__metadata.etag,
"X-Http-Method": "MERGE"
}
});
return call;
}
You need to put this operation in a separated request.
BR
I have two Question Regarding Rest API in EXTJS.
How can I use fields to make rest URL dynamic?
How can I add authentication key to access Context.io in my Rest.Proxy?
This is my solution, but I am not sure if I have done it properly, or not. I am pretty new in ExtJS, so my question may be basic, but I appreciate your help.
Ext.define("EmailFolders", {
extend: "Ext.data.Model",
fields: ["id", "label"],
proxy: {
type: "rest",
url: "lite/users/:" + id + "/email_accounts/:" + label + "/folders"
},
reader: {
type: "json"
},
headers: {
CONSUMER_KEY: "KEY FROM CONTEX.IO",
CONSUMER_SECRET: "SECRET FROM CONTEXT.IO"
}
});
You could use store.getProxy() to make rest URL dynamic and to pass the authentication keys in headers. Proxy have methods
proxy.setUrl() to sets the value of url.
proxy.setHeaders() to sets the value of headers.
You can check here with working fiddle
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
let url = 'https://jsonplaceholder.typicode.com/users';
// Set up a model to use in our Store
Ext.define('User', {
extend: 'Ext.data.Model',
proxy: {
type: 'ajax',
reader: {
type: 'json',
rootProperty: ''
}
}
});
Ext.define('MyStore', {
extend: 'Ext.data.Store',
model: 'User',
listeners: {
beforeload: function (store) {
var proxy = store.getProxy();
//if you want, you can also set here url inside of beforeload
//proxy.setUrl(url);
/*
* You can use {proxy.setHeaders} to set the values from CONTEX.IO
* After ajax request see your request parameter in network analysis below 2 headers are passed in request header
*/
proxy.setHeaders({
CONSUMER_KEY: "KEY FROM CONTEX.IO",
CONSUMER_SECRET: "SECRET FROM CONTEXT.IO"
});
}
}
});
let store = new MyStore();
//Set the dynamic url here
//This {url} will be dynamic whatever you want to pass
store.getProxy().setUrl(url);
store.load(function (data) {
console.log(data);
alert('Open console to see reposne..!')
});
/*
You can also pass url inside of load funtion
*/
new MyStore().load({
url: url + '/' + 1,
callback: function (data) {
console.log(data);
}
});
}
});
Here is the link to get file name. But I want to get the Folder names using REST query. Please Help
For me it was "RootFolder/ServerRelativeUrl"
SharepointAPI.GetLists({params:{$select:"Id,Title,EntityTypeName,RootFolder/ServerRelativeUrl",$expand:"RootFolder"}}).$promise.then(function(result) {
...
});
this.GetLists = function(params) {
return {$promise:
$http({
method: 'GET'
, url: app_web_url+"/_api/web/lists"
, params: params.params
, headers: {
"accept": "application/json; odata=verbose"
}
})
.then(function(response) {
return response.data;
})
};
};
Try calling this endpoint:
/_api/web/Lists/GetByTitle('Site Assets')/Items?$expand=Folder&$select=Title,Folder/ServerRelativeUrl
I am trying to upload a file through a form submit using Ext.Direct, however Ext.direct is sending my request as type 'application/json' instead of 'multipart/form-data'
Here is my form.
{
xtype: 'form',
api: {
submit: 'App.api.RemoteModel.Site_Supplicant_readCSV'
},
items: [
{
xtype: 'filefield',
buttonOnly: false,
allowBlank: true,
buttonText: 'Import CSV'
}
],
buttons:
[
{
text: 'Upload',
handler: function(){
var form = this.up('form').getForm();
if(form.isValid()){
form.submit({
waitMsg: 'Uploading...',
success: function(form, action){
console.log(action.result);
}
});
}
}
}
]
},
On the HTTP request, it checks to see if the request options is a form upload.
if (me.isFormUpload(options)) {
which arrives here
isFormUpload: function(options) {
var form = this.getForm(options);
if (form) {
return (options.isUpload || (/multipart\/form-data/i).test(form.getAttribute('enctype')));
}
return false;
},
getForm: function(options) {
var form = options.form || null;
if (form) {
form = Ext.getDom(form);
}
return form;
},
However, options looks like this
{
callback: function (options, success, response) {
jsonData: Object
action: "RemoteModel"
data: Array[1]
0: form
length: 1
__proto__: Array[0]
method: "Site_Supplicant_readCSV"
tid: 36
type: "rpc"
__proto__: Object
scope: constructor
timeout: undefined
transaction: constructor
}
And there is no direct form config, but it exists in jsonData.data[0]. So it doesn't set it as type multipart/form-data and it gets sent off as type application/json.
What am I doing wrong? Why isn't the form getting submitted properly?
Edit - I am seeing a lot of discussion about a 'formHandler' config for Ext.Direct? I am being led to assume this config could solve my issue. However I don't know where this should exist. I'll update my post if I can find the solution.
Solution - Simply adding /formHandler/ to the end of the params set the flag and solved my issue. Baffled.
Supplicant.prototype.readCSV = function(params,callback, request, response, sessionID/*formHandler*/)
{
var files = request.files;
console.log(files);
};
The method that handles file upload requests should be marked as formHandler in the
Ext.Direct API provided by the server side.
EDIT: You are using App.api.RemoteModel.Site_Supplicant_readCSV method to upload files; this method needs to be a formHandler.
I'm not very familiar with Node.js stack but looking at this example suggests that you may need to add /*formHandler*/ descriptor to the function's declaration on the server side.