Help with File Upload
Help with File Upload
Hi all, I am using NodeJS, Express and DataTables.net Editor module. I have a page that allows me to add a general URL link and I would like to add an icon for the link. The current solution works perfectly to add a link, but the file upload is giving an issue.
Within my application I am using csurf for CSRF protection. In my page javascript I send the _csrf as part of ajax data.
// Ajax definition:
editor = new $.fn.dataTable.Editor({
ajax: {
url: "/api/links",
data: {
"_csrf" : "<%= csrfToken %>"
}
},
As mentioned this works fine for the data itself. For the file upload I have the following:
// File Upload section:
{
label: "Icon",
name: "links.icon",
type: "upload",
display: function (file_id) {
if (file_id !== 'null' && file_id) {
return '<img src="' + editor.file('icons', file_id).web_path + '"/>';
}
},
clearText: "Clear",
noImageText: 'No Image',
ajax: {
url: "/api/links",
data: {
"_csrf" : "<%= csrfToken %>"
}
},
}
I have tried various options with no success.
Any ideas would be appreciated.
Full source code for the page:
<%- include('./includes/head.ejs') %>
</head>
<body>
<%- include('./includes/navigation.ejs') %>
<main class="main">
<div class="container-fluid">
<div id="list" class="row">
<div class="col-lg-4">
<button id="addLink" class="btn">Add Link</button>
</div>
<div class="col">
<input id="searchText" class="active" placeholder="enter search...">
</div>
</div>
<div class="container-fluid">
<div id="cards" class="row">
</div>
</div>
</div>
</main>
<%- include('./includes/end-scripts.ejs') %>
<script type="text/javascript">
var editor;
function createCard(data) {
var id = data.DT_RowId;
var html =
'<div class="card col-sm-3" data-editor-id="' + id + '" id="' + id + '" data-name="' + data.links.name + '">' +
'<div class="card-header">' +
'<a class="hidden" data-editor-field="links.uuid">' + data.links.uuid + '</a>' +
'<h5 class="card-title" data-editor-field="links.name">' + data.links.name + '</h5>' +
'</div>' +
'<div class="card-body">' +
'<p class="card-text">' +
'<p>Description:</p>' +
'<p data-editor-field="links.description">' + data.links.description + '</p>' +
'<p data-editor-field="links.icon">' + data.links.icon + '</p>' +
'<a href="' + data.links.url + '" target="_blank" data-editor-field="links.url">' + data.links.url + '</a>' +
'</p>' +
'</div>' +
'<div class="card-footer text-center">' +
'<button data-id="' + id + '" data-name="' + data.links.name + '" class="btn btn-sized edit">Edit</button>';
//TODO
// Add code to only allow delete if user is admin
//if (!data.menus.locked) {
html = html + '<button data-id="' + id + '" data-name="' + data.links.name + '" class="btn btn-sized-danger delete">Delete</button>'
// }
html = html + '</div>' +
'</div>';
$(html).appendTo('#cards');
}
<!--$.ajaxSetup({-->
<!--headers: {-->
<!--'CSRFToken': "<%= csrfToken %>"-->
<!--},-->
<!--data: function(id) {-->
<!--d._csrf = "<%= csrfToken %>"-->
<!--}-->
<!--});-->
$(document).ready(function () {
editor = new $.fn.dataTable.Editor({
ajax: {
url: "/api/links",
data: {
"_csrf" : "<%= csrfToken %>"
}
},
// template: "#customForm",
fields: [
{
label: "uuid",
name: "links.uuid",
type: "hidden"
},
{
label: "Name",
name: "links.name",
// fieldInfo: "The job role name. This must be unique"
},
{
label: "Description",
name: "links.description",
// fieldInfo: 'The job role description'
},
{
label: "URL",
name: "links.url"
},
{
label: "Icon",
name: "links.icon",
type: "upload",
display: function (file_id) {
if (file_id !== 'null' && file_id) {
return '<img src="' + editor.file('icons', file_id).web_path + '"/>';
}
},
clearText: "Clear",
noImageText: 'No Image',
ajax: {
url: "/api/links",
data: {
"_csrf" : "<%= csrfToken %>"
}
},
}
]
});
editor.on('submitSuccess', function (e, json, data, action) {
if (action === 'create') {
createCard(data);
}
});
$('#addLink').on('click', function () {
// editor.field('links.name').enable();
// editor.set('job_roles.locked', 'false');
editor
.title('Create New Link')
.buttons('Create', 'Cancel')
.create();
});
$('#cards').on('click', 'button.edit', function () {
// editor.field('links.name').disable();
editor
.title('Edit Link: ' + $(this).data('name'))
.buttons('Save')
.edit($(this).data('id'));
});
$('#cards').on('click', 'button.delete', function () {
editor
.title('Delete Link: ' + $(this).data('name'))
.buttons('Delete')
.message('Are you sure you want to delete this link?')
.remove($(this).data('id'));
});
$.ajax({
url: '/api/links',
dataType: 'json',
method: 'GET',
success: function (json) {
for (var i = 0, ien = json.data.length; i < ien; i++) {
createCard(json.data[i])
}
}
});
});
</script>
<%- include('./includes/end.ejs') %>
This question has an accepted answers - jump to answer
Answers
Is the csrf middleware rejecting the upload? If you look in the browser's network inspector for the "header" data (i.e. what was sent to the server) on upload, does it include the csrf code given in the
data
property?If not, could you try:
Thanks,
Allan
Allan,
I have added that into the code and it still gives me the same error. The req data in the server is:
I have managed to solve the issue by using CSRF's header abilities.
As in using
ajax: { headers: ... }
?Thanks,
Allan
Yes. That passes the correct information to csurf. I am now getting a different error when trying to upload the file. It is giving me a "Uncaught Unknown file table name: files" on the client side and the following on the serverside
I have copied the example from the Editor example downloads.
Here is my code serverside code.
I have tried it with and without the leftjoin to the 'files' table.
Any ideas of what I am doing wrong here?
Here is my ejs as well.
Can you show me the JSON return from the server when you upload a file please?
Allan
Hi Allan
If I try the code with a join to the files table (as above) I get this. The links.icon is populated as options with the files, but the files subtable is empty.
If I remove the options and the join (as per the example) it returns a blank set as well for files.
Hi Allan,
Once I added the DataTable to the page it all worked. So you cannot use file upload with Editor in standalone mode.
Regards
The file information is retrieved by DataTables' Ajax request when populating the data into the table (Editor listens for the
xhr
event to see when that happens). In standalone mode there is no Ajax request to piggyback that information onto, so in that mode, you'd need to populate the data for existing files by making an Ajax request to get that data and then assigning it to$.fn.dataTable.Editor.files[ table ]
.That should happen automatically when uploading a new file in standalone mode though - its just the initial population that would be a problem.
Allan