Project

General

Profile

Support #8707

How to upload a file with javascript?

Added by Jocelyn Martin about 1 month ago. Updated 13 days ago.

Status:
New
Priority:
Normal
Assignee:
-
Target version:
-
Start date:
06/17/2021
Due date:
% Done:

0%

Estimated time:

Description

Hello everybody,

WFileUpload allow to upload files, it is working fine for me and it is nice.
But now I want to upload some sounds recorded by the microphones too.
I don't think this is possible with WFileUpload.

So I try to do it in html, javascript, php by following some exemples on the web.
I inject html code like this:

wContainerWidgetObject->addNew<Wt::WText>("<html code>", Wt::TextFormat::UnsafeXHTML);

and I add the .js and .php files.

No matter of how I do it with XMLHttpRequest (like here https://blog.addpipe.com/using-recorder-js-to-capture-wav-audio-in-your-html5-web-site/) or with the most common way with ajax (like here https://makitweb.com/how-to-upload-image-file-using-ajax-and-jquery/), I always come to a point where I have no error on the console, everything seems to be ok but I notice that the file is not uploaded on the server.
There is something that forbid to do it? There is something to set the wt config xml file for that?
I already tried to set big number for "max-memory-request-size", "max-request-size" and "max-formdata-size", but I still have the problem. (and again with WFileUpload it is working)

(For the ajax way I even try to modify the jquery.min.js to have this function, after that the function was found but still no file is uploaded)

Thank you for your help,
Wt is really nice in general.

#1

Updated by Korneel Dumon about 1 month ago

Hi,

to upload a file, the easiest way is to create a WResource. When you send data to the url of the resource, it will be available to you in WResource::handleRequest(), at which point you can save it to a file. This is also sort of how WFileUpload works internally.

I guess your way of injecting JS will work, but Wt actually has some facilities for this, have a look at:

  • WApplication::require()
  • WApplication::doJavaScript()
  • WWidget::doJavaScript()
  • Wt::JSignal / Wt::JSlot

I'm not sure which of these is most useful to you, it depends a bit on your design.

#2

Updated by Jocelyn Martin 23 days ago

I did that according to your answer.

  // Javascript for audio recording
  Wt::WApplication::instance()->require("https://cdn.rawgit.com/mattdiamond/Recorderjs/08e7abd9/dist/recorder.js");

  // Button to start the recording
  auto* startRecordBtn = changeLanguageTemplate->addNew<Wt::WPushButton>("start record");
  // Button to stop the recording
  auto* stopRecordBtn = changeLanguageTemplate->addNew<Wt::WPushButton>("stop record");
  stopRecordBtn->setEnabled(false);

  startRecordBtn->clicked().connect([=] {
    startRecordBtn->setEnabled(false); // FIXME: this should be done only if "navigator.mediaDevices.getUserMedia(constraints)" succeeded
    stopRecordBtn->setEnabled(true); // FIXME: this should be done only if "navigator.mediaDevices.getUserMedia(constraints)" succeeded
    startRecordBtn->doJavaScript(
          "console.log(\"startRecordBtn clicked\");"
          "var constraints = { audio: true, video:false }                                 \n"
          "navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {       \n"
          "  audioContext = new AudioContext();                                           \n"
          "  gumStream = stream;                                                          \n"
          "  input = audioContext.createMediaStreamSource(stream);                        \n"
          "  rec = new Recorder(input,{numChannels:1})                                    \n"
          "  rec.record()                                                                 \n"
          "  console.log(\"Recording started\");                                          \n"
          "}).catch(function(err) {                                                       \n"
          "  console.log(\"Error: \" + err);                                              \n"
          "});");
  });

  stopRecordBtn->clicked().connect([=] {
    startRecordBtn->setEnabled(true);
    stopRecordBtn->setEnabled(false);
    stopRecordBtn->doJavaScript(
          "console.log(\"stopButton clicked\");                                           \n"
          "//tell the recorder to stop the recording                                      \n"
          "rec.stop();                                                                    \n"
          "                                                                               \n"
          "//stop microphone access                                                       \n"
          "gumStream.getAudioTracks()[0].stop();                                          \n"
          "                                                                               \n"
          "//create the wav blob and pass it on to createDownloadLink                     \n"
          "rec.exportWAV(function (blob) {                                                \n"
          "  console.log(\"afer export WAV: \" + blob);                                   \n"
          "});");
  });

But I still don't see how to have a WResource pointing to the blob object that is representing the WAV. (cf last lines of this code example)
If I succeed to do it I am ok to propose a merge request to add a widget for audio recording on Wt and to add an example project that uses it like you are used to do it.

#3

Updated by Korneel Dumon 13 days ago

Hi,

seems like you get the data in the handler of exportWAV. From this handler, I would make a POST request with the blob to the url of your WResource.

Also available in: Atom PDF