Synchronous Uploader in a Grid

Hello,

So I am trying to use the uploader component in a grid but in synchronous mode.  I have it displaying correctly and everything seems to be working correctly, except when I click the save button for the grid dialog, it is sending a string of the file up and not the binary.  I assume I am doing the read function incorrectly.  Please see the below code:


            var elem;
            var uploadObj;
            var readfile = "uploaded";
            var grid = new ej.grids.Grid({
                dataSource: dataManager,
                query: new ej.data.Query().addParams('task_id'args.data.id),
                allowFiltering: true,
                allowSelection: true,
                allowSorting: true,
                allowTextWrap: true,
                editSettings: {
                    allowAdding: true,
                    allowDeleting: true,
                    allowEditing: true,
                    mode: 'Dialog',
                    showDeleteConfirmDialog: true
                },
                filterSettings: {type: 'Excel'},
                actionBegin: function(args){
                    if (args.requestType === 'add' || args.requestType === 'beginEdit'){
                        this.columns[1].visible = false;
                        this.columns[2].visible = false;
                        this.columns[3].visible = false;
                    }
                },
                actionComplete: function(args){
                    if(args.requestType === 'beginEdit' || args.requestType === 'add'){
                        args.dialog.header = (args.requestType === 'beginEdit'? 'Edit Attachment' : 'Add Attachment to Task';
                    } else {
                        this.columns[1].visible = true;
                        this.columns[2].visible = true;
                        this.columns[3].visible = true;
                    }
                },
                actionFailure: actionFailure,
                toolbar: ['Add','Edit','Update','Delete','Cancel','Search'],
                columns: [
                    {
                        field: 'id', headerText: 'ID', isPrimaryKey: true, visible: false,
                        validationRules: {required: true, number: true},
                    },
                    { field: 'name', headerText: 'Name', allowEditing: false, allowAdding: false},
                    { field: 'size', headerText: 'Size', allowEditing: false, allowAdding: false},
                    { field: 'type', headerText: 'Type', allowEditing: false, allowAdding: false},
                    { field: 'approval_required', headerText: 'Approval?', dataSource: arrNoYes, foreignKeyField:'id', foreignKeyValue:'text',  textAlign: 'Center' },
                    { field: 'signing_user_id', headerText: 'Signer',dataSource: users, foreignKeyField:'id', foreignKeyValue:'full_name',},
                    { field: 'signed_at', headerText: 'Date Signed',type: 'date', format: 'MM/dd/yyyy HH:mm', editType: 'datetimepickeredit', edit: {params: {format: 'MM/dd/yyyy HH:mm'}}},
                    { field: 'fileupload', headerText: 'Document', allowEditing: false,
                        edit: {
                            create: function(args){
                                readfile = args.data.path;
                                elem = document.createElement('input');
                                return elem;
                            },
                            read: function(args) {
                                if(uploadObj.filesData[0]){
                                    readfile = uploadObj.filesData[0].rawFile instanceof File ? uploadObj.filesData : readfile;
                                }
                                return readfile;
                            },
                            destroy: function() {
                                uploadObj.destroy();
                            },
                            write: function(args){
                                uploadObj = new ej.inputs.Uploader({
                                    autoUpload: false,
                                    multiple: false,
                                    allowedExtensions: '.jpg,.png,.pdf,.doc,.docx,.ppt,.pptx',
                                    maxFileSize: 49000000,
                                });
                                uploadObj.appendTo(elem);
                            }
                        }
                    },
                ],
            });
            grid.appendTo('#attachments');
        }

5 Replies 1 reply marked as answer

PG Praveenkumar Gajendiran Syncfusion Team September 14, 2021 08:21 AM UTC

Hi Mark,

Thanks for contacting Syncfusion support.

We are not able to clearly understand your requirement from the provided information, So we need the following details to understand the query better at our end. So kindly share the following details.  
  1. Do you wish to upload the file in the dataSource during insert operation and then show the file name only in the Grid column or you want to render the file name as anchor link in the Grid column so you can able to download the corresponding file when click anchor link(file name) in Grid? If so, please let us know what type of adaptor you are used to binding the data in the Grid? and share your data structure example.
  2. Or, If you want to upload the image file in the Grid and show the image in the Grid column, we suggest you to refer the below KB link to achieve your requirement,
    KB Link: https://www.syncfusion.com/kb/12693/how-to-edit-the-column-in-grid-using-the-uploader-control
  3. Please elaborate on your exact requirement scenario with more details, if possible share us a pictorial representation based on which we will check from our end and provide the further details.
Please get back to us with the requested details which will be helpful for us to validate the reported scenario at our end and provide the solution as early as possible 

Regards 
Praveenkumar G 



MA Mark September 14, 2021 01:20 PM UTC

Option 1 is what we are trying to do. We just need the file name to be shown as the file is being saved in S3 bucket and we will need to do a temporary URL to download - which we already have code for. This is our dataManager:


var dataManager = new ej.data.DataManager({
url: '/api/Attachments/list',
crudUrl: '/api/Attachments/crud',
adaptor: new ej.data.UrlAdaptor(),
crossDomain: true,
headers: [{"Authorization": "Bearer {{Auth::User()->api_token}}"}]
});

Data structure:

{"count":1,"result":[{"id":1,"task_id":53,"name":"Sample PO","size":186425,"type":"pdf","s3_path":"attachments\/234cuyC33P3j4r94CHsrZ4.pdf","signing_user_id":1,"signed_at":null,"approval_required":1,"created_at":"2021-08-14T06:01:35.000000Z","created_by":1,"updated_at":"2021-08-14T06:01:35.000000Z","updated_by":1,"deleted_at":null,"deleted_by":null}]}


We need to do synchronous and save the file on insert because we need new record id for association in S3 bucket.

So to be clear, the anticipated behavior is that a user clicks Add for the grid, the dialog is shown, they fill out the form,

browse for the file and the uploader component acts like a regular input type="file" and then on Save, the file is

submitted using the grids crudUrl to the server.



PG Praveenkumar Gajendiran Syncfusion Team September 15, 2021 02:15 PM UTC

Hi Mark, 

Thanks for your update. 

Based on your query and provided information, We have prepared a sample. In this sample, we have overridden the default functionally of adaptor and upload file during insert operation and then render file name as anchor link in grid mode using template property so you can able to download the corresponding file when click anchor link(file name) in Grid.  

By default , When we upload files in server then its needed to create a FormData and if we want to send the additional information then we have to append the value in FormData as follows, then only we  can able to get the value in controller side.  

Here, we have append the OrderID and CustomerID in FormData and get it in controller Save method(Insert method) and the insertion action was works fine and then the ModelState.IsValid  property returns the value true. Please refer the below sample, code example and screenshot for more information.

Sample: https://www.syncfusion.com/downloads/support/forum/168817/ze/ej2-uploader-core-services943619615.zip 

[HomeController.cs] 

 

   

Index.cshtml  
 
<div id="container"> 
    <div id="Grid"></div> 
</div> 
<script id="template2" type="text/x-template"> 
    <div class="link"> 
        <a rel='nofollow' href=""></a> 
    </div> 
</script> 
<script> 
    var file; 
    var elem; 
    var richText; 
    var rte; 
    class custom extends ej.data.UrlAdaptor { 
 
        processResponse(data, ds, query, xhr, request, changes) { 
            request.data = JSON.stringify(data); 
            return ej.data.UrlAdaptor.prototype.processResponse.call(this, data, ds, query, xhr, request, changes) 
        } 
        insert(dm, data, tableName) { 
            var fd = new FormData(); 
            for (var prop of data.file) { 
                fd.append('UploadFiles', prop.rawFile); 
            } 
            fd.append('OrderID', data.OrderID); 
            fd.append('CustomerID', data.CustomerID); 
            // data.File = fd; 
            return { 
                url: dm.dataSource.insertUrl || dm.dataSource.crudUrl || dm.dataSource.url, 
                type: "POST", 
                data: fd, 
                contentType: null 
            } 
        } 
        update(dm, data, tableName) { 
            var fd = new FormData(); 
            for (var prop of tableName.file) { 
                fd.append('UploadFiles', prop.rawFile); 
            } 
            fd.append('OrderID', tableName.OrderID); 
            fd.append('CustomerID', tableName.CustomerID); 
            // data.File = fd; 
            return { 
                url: dm.dataSource.updateUrl || dm.dataSource.crudUrl || dm.dataSource.url, 
                type: "POST", 
                data: fd, 
                contentType: null 
            } 
        } 
    }; 
    let data = new ej.data.DataManager({ 
        url: "/Home/UrlDatasource", 
        insertUrl: "/Home/Save", 
        updateUrl: "/Home/Update", 
        removeUrl: "Home/Delete", 
        adaptor: new custom 
    }); 
    
    let grid = new ej.grids.Grid({ 
        dataSource: data, 
        editSettings: { allowEditing: true, allowAdding: true, allowDeleting: true, mode: 'Dialog' }, 
        allowPaging: true, 
        toolbar: ['Add', 'Edit', 'Delete'], 
        columns: [ 
            { field: 'OrderID', headerText: 'Order ID', textAlign: 'Right', width: 100, isPrimaryKey: true }, 
            { field: 'CustomerID', headerText: 'Customer ID', width: 120 }, 
            { 
                field: 'file', headerText: "File", type: 'string', template: "#template2", width: 180, edit: { 
                    //cellEditTemplate 
                    create: () => { 
                        // Input element is created and returned for appending the Uploader control. 
                        elem = document.createElement('input'); 
                        return elem; 
                    }, 
                    read: () => { 
                        //read function is used to read the value from the component at the time of save. 
                        return (file) ? file : uploadObj.filesData; 
                    }, 
                    destroy: () => { 
                        // Uploader is destroyed on edit save/close action. 
                        uploadObj.destroy(); 
                    }, 
                    write: args => { 
                        //write function is used to create custom component or assign default value at the time of editing. 
                        uploadObj = new ej.inputs.Uploader({ 
                            files: [''] 
                        }); 
                        uploadObj.appendTo(elem) 
       } 
                } }, 
 
        ], 
        height: 265, 
        queryCellInfo: queryCellInfo, 
        actionComplete: complete, 
    }); 
    grid.appendTo('#Grid'); 
   
    function queryCellInfo(args) { 
        if (args.column.field === 'file') { 
            if (args.data.file) { 
                var anchotEle = args.cell.getElementsByTagName('a')[0]; 
                anchotEle.innerText = args.data.file.name; 
                anchotEle.onclick = function click(args) { 
                    args.target.setAttribute("rel='nofollow' href", http://localhost:63371/Home/Download?filename= + args.target.innerText); 
                }; 
            } 
        } 
    } 
    function complete(args) { 
        if (args.requestType === 'add') { 
            args.form.setAttribute('enctype', 'multipart/form-data'); 
            args.form.setAttribute('encoding', 'multipart/form-data'); 
        } 
        if (args.requestType === 'save' && args.action === "edit") { 
            var gridInstance = document.getElementById('Grid').ej2_instances[0]; //Grid Instance 
            gridInstance.refresh(); 
        } 
    } 
</script> 

Screenshot: 
 

Please get back to us if you need further assistance. 

Regards,
Praveenkumar G  



MA Mark September 15, 2021 10:43 PM UTC

Thank you, I guess I can figure this out. This is all Razor and .Net right?

Edit: I was able to get this working. For anyone else who may need it, here you go (you may need to add update function in your adaptor depending on how your server process is looking for data):


class attachmentAdaptor extends ej.data.UrlAdaptor {
processResponse(data, ds, query, xhr, request, changes) {
request.data = JSON.stringify(data);
return ej.data.UrlAdaptor.prototype.processResponse.call(this, data, ds, query, xhr, request, changes);
}
insert(dm, data, tableName) {
var fd = new FormData();
var dt = null;
if(data.signed_at) dt = new Date(data.signed_at).toISOString().slice(0, 19).replace('T', ' ');
fd.append('approval_required', data.approval_required);
fd.append('signing_user_id', data.signing_user_id);
fd.append('signed_at', dt);
fd.append('fileupload', data.fileupload);
fd.append('task_id', task_id);
fd.append('action', 'insert');

return {
url: dm.dataSource.crudUrl,
type: "POST",
data: fd,
contentType: null
}
}
};

var task_id=0;
function createAttachmentsGrid(args) {
task_id = args.data.id;
if(!$('#attachments').hasClass('e-grid')) {
var dataManager = new ej.data.DataManager({
url: '/api/Attachments/list',
crudUrl: '/api/Attachments/crud',
adaptor: new attachmentAdaptor(),
crossDomain: true,
headers: [{"Authorization": "Bearer {{Auth::User()->api_token}}"}]
});
var elem;
var uploadObj;
var readfile = "uploaded";
var file;

var grid = new ej.grids.Grid({
dataSource: dataManager,
query: new ej.data.Query().addParams('task_id', args.data.id),
allowFiltering: true,
allowSelection: true,
allowSorting: true,
allowTextWrap: true,
editSettings: {
allowAdding: true,
allowDeleting: true,
allowEditing: true,
mode: 'Dialog',
showDeleteConfirmDialog: true
},
filterSettings: {type: 'Excel'},
actionBegin: function(args){
if (args.requestType === 'add' || args.requestType === 'beginEdit'){
this.columns[1].visible = false;
this.columns[2].visible = false;
this.columns[3].visible = false;
if(args.requestType === 'beginEdit') this.columns[7].visible = false;
}
},
actionComplete: function(args){
if(args.requestType === 'beginEdit' || args.requestType === 'add'){
args.dialog.header = (args.requestType === 'beginEdit') ? 'Edit Attachment' : 'Add Attachment to Task';
}
this.columns[1].visible = true;
this.columns[2].visible = true;
this.columns[3].visible = true;
this.columns[7].visible = true;
},
actionFailure: actionFailure,
queryCellInfo: function(args){
if (args.column.field === 'fileupload') {
if (args.data.name) {
var anchorEle = args.cell.getElementsByTagName('a')[0];
anchorEle.innerText = args.data.name+'.'+args.data.type;
anchorEle.onclick = function click(args) {
args.target.setAttribute("rel='nofollow' rel='nofollow' href", args.target.innerText);
};
}
}
},
toolbar: ['Add','Edit','Update','Delete','Cancel','Search'],
columns: [
{
field: 'id', headerText: 'ID', isPrimaryKey: true, visible: false,
validationRules: {required: true, number: true},
},
{ field: 'name', headerText: 'Name', allowEditing: false, allowAdding: false},
{ field: 'size', headerText: 'Size', width: 100, allowEditing: false, allowAdding: false},
{ field: 'type', headerText: 'Type', width: 100, allowEditing: false, allowAdding: false},
{ field: 'approval_required', headerText: 'Approval?', dataSource: arrNoYes, foreignKeyField:'id', foreignKeyValue:'text', textAlign: 'Center' },
{ field: 'signing_user_id', headerText: 'Signer',dataSource: users, foreignKeyField:'id', foreignKeyValue:'full_name',},
{ field: 'signed_at', headerText: 'Date Signed',type: 'date', format: 'MM/dd/yyyy HH:mm', editType: 'datetimepickeredit', edit: {params: {format: 'MM/dd/yyyy HH:mm'}}},
{ field: 'fileupload', headerText: 'Document', allowEditing: false, type: 'string', template: "#linkTemplate",
edit: {
create: function(f){
readfile = f.data.s3_path;
elem = document.createElement('input');
return elem;
},
read: function(f) {
if(uploadObj.filesData[0]){
readfile = uploadObj.filesData[0].rawFile instanceof File ? uploadObj.filesData[0].rawFile : readfile;
}
return readfile;
},
destroy: function() {
if(uploadObj) uploadObj.destroy();
},
write: function(f){
uploadObj = new ej.inputs.Uploader({
autoUpload: false,
multiple: false,
allowedExtensions: '.jpg,.png,.pdf,.doc,.docx,.ppt,.pptx',
maxFileSize: 49000000,
});
uploadObj.appendTo(elem);
}
}
},
],
});
grid.appendTo('#attachments');
}
}


Marked as answer

SK Sujith Kumar Rajkumar Syncfusion Team September 16, 2021 07:24 AM UTC

Hi Mark, 

Thanks for the update and sharing your solution here. We are glad to hear that your query has been resolved. 

Regards, 
Sujith R 


Loader.
Up arrow icon