Managing Server Part of Uploading

Server Script

In essence, file uploading is done via Ajax. Each time the send() function is executed, an Ajax POST request is sent behind the scene. Its url is a script you specify as a value of the upload property.

{view:"uploader", name:"uploader", upload:"server/upload"}

You can write a custom script in your favorite language whether it is PHP, NodeJS, etc. Regardless of the language, the script must contain:

  • the desired destination for file uploading
  • script response in form of a JS string - {"status":"server"} for success, {"status":"error"} for failure.

Below NodeJS solution is explained:

In the example below Busboy module is used to parse incoming form data. When Busboy receives a file, the module calls its file event, so you can make use of this event to put the file into the desired catalogue.

First, provide a name for the file and encode it with MD5:

const Busboy = require("busboy");
//...
app.post(root + "/upload",(req,res)=>{
  var busboy = new Busboy({ headers: req.headers });
  var saveTo = ""; 
  var fileName = ""; 
 
  busboy.on("file", (field, file, name) => {
    fileName = path.basename(name);
    fileName = crypto.createHash("md5").update(fileName).digest("hex");
  });
  // ...
})

Then define a script path to send the file to:

busboy.on("file", (field, file, name) => {
  //...
  saveTo = path.join(__dirname, "uploads", "photos", fileName);
  file.pipe(fs.createWriteStream(saveTo));
});

Tuning Server-side Response

You must also tune the server response to notify about the result of file uploading.

The script ought to return JSON string that is later processed by Uploader to change the properties of the corresponding file object. Uploader expects an object with two fields:

  • status ("server" if the uploading is successful)
  • value with a name the file received from the backend.

In the example below the Busboy's finish event is used to return the server response.

app.post(root + "/upload",(req,res)=>{
  // ...
  busboy.on("finish", function() {
    if (saveTo){
      let fileName = path.basename(saveTo);
      res.send({
        status: "server",         value: fileName         });
    }
  });
 
  return req.pipe(busboy);
})

Why is it done in the described way? Each file object features status that changes during uploading:

  • client - when the file was just added to Uploader and uploading hasn't started yet. Or when uploading was aborted by a user
  • transfer - during uploading until a script response
  • server - uploading finished, set when the script response is "{status:'server'}"
  • error - an error has occurred during uploading, set when the script response is {'status':'error'}.

The response is available directly in the send() callback that takes it as a parameter:

$$("uploader1").send(function(response){
  if(response)
    webix.message(response.status);
    webix.message(response.sname);
});

Related sample:  Sending on Custom Action

Multiple Files

In case of multiple files uploaded at a time, a direct response isn't suitable, as it contains info about one file.

Instead, start a cycle that will get to each file's value:

$$("uploader1").send(function(){
    $$("uploader1").files.data.each(function(obj){
        var status = obj.status;
        var name = obj.name;
        if(status === "server"){
            var sname = obj.sname; //came from upload script
            webix.message("Upload: "+status+" for "+ name+" stored as "+sname );
        }
        else{
            webix.message("Upload: "+status+" for "+ name);
        }
  })
})

Related sample:  Uploader and Form Integration

Files Data Array

The same can be done by addressing directly to the uploader datastore, through the data array:

$$("uploader1").send(function(){
    var text = f.data.pull[file_id].sname;
    webix.message("Test sname: "+ text);
});

Or, in a cycle in case of multiple files uploaded at a time:

for(var i in f.data.pull){
    var text = f.data.pull[i].sname;
    webix.message("Test sname: "+ text);
}

Setting the Uploading Button Name

By default, the value of a button for uploading files is "upload". If you want to set your own name for this button, you need to make use of the inputName property:

{ view:"uploader", inputName:"myFile" }
Back to top