5

I have autoUpload set to false, as I want to upload the images myself to my backend. However, to do this I first need the file object. In the callbacks onSubmitted event I'm trying to pass the images id to the getFile method, to return the object. However, when I try to do this I get the below error message.

in onSubmitted: id=0 | name=28603454_15219061700_r.jpg index.js:2178

[Fine Uploader 5.16.2] Caught exception in 'onSubmitted' callback - Cannot read property 'uploader' of null

I'm guessing I get this because I'm declaring a const object and referencing it at the same time, which I believe you cannot do...

So, any ideas on how I can call methods within the callbacks function? Or is there another way?

const uploader = new FineUploaderTraditional({
  options: {
    maxConnections: 1,
    autoUpload: false,
    deleteFile: { enabled: true, endpoint: "/uploads" },
    request: { endpoint: "/uploads" },
    retry: { enableAuto: true },
    callbacks: {
      onSubmitted: function(id, name) {
        console.log("in onSubmitted: id=" + id + " | name=" + name);
        // getFile(id) returns a `File` or `Blob` object.
        console.log(this.uploader.getFile(id));
      }
    }
  }
});

Update I've now taken all of my fine-uploader code and created a new component with it. I'm still facing the same problems. The component code below:

FineUploader.jsx

import React, { Component } from "react";
import FineUploaderTraditional from "fine-uploader-wrappers";
import Gallery from "react-fine-uploader";
import Filename from "react-fine-uploader/filename";
import "react-fine-uploader/gallery/gallery.css";

const util = require("util");

const uploader = new FineUploaderTraditional({
  options: {
    // debug: true,
    maxConnections: 1,
    autoUpload: false,
    deleteFile: { enabled: true, endpoint: "/uploads" },
    request: { endpoint: "/uploads" },
    retry: { enableAuto: true },
    validation: {
      acceptFiles: ".jpg,.png,.gif,.jpeg",
      allowedExtensions: ["jpg", "png", "gif", "jpeg"],
      itemLimit: 5,
      sizeLimit: 5000000
    },
    callbacks: {
      onCancel: function() {
        console.log("in onCancel: ");
      },
      onComplete: function(id, name, responseJSON, xhr) {
        console.log("in onComplete: " + id + " | " + name + " | " + responseJSON + " | " + xhr);
      },
      onAllComplete: function(succeeded, failed) {
        console.log("in onAllComplete: " + succeeded + " | " + failed);
      },
      onProgress: function(id, name, uploadedBytes, totalBytes) {
        console.log("in onProgress: " + id + " | " + name + " | " + uploadedBytes + " | " + totalBytes);
      },
      onError: function(id, name, errorReason, xhr) {
        console.log("in onError: " + id + " | " + name + " | " + errorReason + " | " + xhr);
      },
      onDelete: function(id) {
        console.log("in onDelete: " + id);
      },
      onDeleteComplete: function(id, xhr, isError) {
        console.log("in onDeleteComplete: " + id + " | " + xhr + " | " + isError);
      },
      onPasteReceived: function(blob) {
        console.log("in onPasteReceived: " + blob);
      },
      onResume: function(id, name, chunkData, customResumeData) {
        console.log("in onResume: " + id + " | " + name + " | " + chunkData + " | " + customResumeData);
      },
      onStatusChange: function(id, oldStatus, newStatus) {
        console.log("in onStatusChange: " + id + " | " + oldStatus + " | " + newStatus);
      },
      onSubmit: function(id, name) {
        console.log("in onSubmit: " + id + " | " + name);
      },
      onSubmitted: function(id, name) {
        console.log("in onSubmitted: id=" + id + " | name=" + name);
        // getFile(id) returns a `File` or `Blob` object.
        // console.log(this.uploader.getFile(id));
        // console.log(uploader.getFile(id));
        // nothing here is working.... :(
      },
      onUpload: function(id, name) {
        console.log("in onUpload: " + id + " | " + name);
      },
      onValidate: function(data, buttonContainer) {
        console.log(
          "in onValidate: " + util.inspect(data, { showHidden: true, depth: null }) + " | " + buttonContainer
        );
      },
      onSessionRequestComplete: function(response, success, xhrOrXdr) {
        console.log("in onSessionRequestComplete: " + response + " | " + success + " | " + xhrOrXdr);
      }
    }
  }
});

const fileInputChildren = <span>Click to Add Photos</span>;
const statusTextOverride = {
  upload_successful: "Success!"
};

class FineUploader extends Component {
  constructor() {
    super();

    this.state = {
      submittedFiles: []
    };
  }

  componentDidMount() {
    uploader.on("submitted", id => {
      const submittedFiles = this.state.submittedFiles;
      console.log("submittedFiles: " + submittedFiles);

      submittedFiles.push(id);
      this.setState({ submittedFiles });
    });
  }

  render() {
    return (
      <div>
        {this.state.submittedFiles.map(id => (
          <Filename id={id} uploader={uploader} />
        ))}
        <Gallery
          fileInput-children={fileInputChildren}
          status-text={{ text: statusTextOverride }}
          uploader={uploader}
        />
      </div>
    );
  }
}

export default FineUploader;

And -- On the main page now, I'm importing FineUploader.jsx, and using the component.

import FineUploader from "../../components/FineUploader";

In my render method I have:

<FineUploader />
Saeed
  • 1,718
  • 1
  • 10
  • 24
ElasticThoughts
  • 3,208
  • 6
  • 41
  • 55

2 Answers2

3

this is tricky in javascript. Within regular functions (e.g., function f(){...}), this depends on where the function is called rather than where it is defined. When using callbacks via a 3rd party api, you don't really have control over where it is called, so you can end up with errors like you have above.

Fortunately, you can use arrow functions (e.g., const f = () => {...};) to bind this based on where the function is defined.

See the MDN docs for more info or you can reference this excellent SO answer.

For your code in particular, however, I am not sure that either of those will work as your this when you define onSubmitted is just the global/window object.

In order for this to work, you need to create a closure at the top level (right before you actually create the uploader):

function onSubmitted(id, name) {
    console.log("in onSubmitted: id=" + id + " | name=" + name);
    // getFile(id) returns a `File` or `Blob` object.
    console.log(uploader.getFile(id));
}

const uploader = new FineUploaderTraditional({..., callbacks: {onSubmitted, ...}});

This will allow you to define the logic for interacting with uploader before you actually instantiate it (which is what it looks like you want). Notice the lack of this as we are simply taking advantage of js closure rules.

Jclangst
  • 974
  • 3
  • 9
0

Instead of console.log(this.uploader.getFile(id)); try:

console.log(uploader.methods.getFile(id));
Hossein Golshani
  • 1,801
  • 5
  • 14
  • 25