filestack / filestack-react

Official React component for Filestack - API and content management system that makes it easy to add powerful file uploading and transformation capabilities to any web or mobile application.
https://www.filestack.com
MIT License
164 stars 40 forks source link

PickerInline && PickerDrop -- complain about missing container #116

Closed ehubbell closed 2 years ago

ehubbell commented 3 years ago

We have a Nextjs application and are conditionally importing this library using next/dynamic and then some adding some inline checks to make sure the window is present before rendering the component that contains filestack-react. When we use the PickerInline or PickerDrop components we get a rendering error that says it can't find container #xyz whereas the PickerOverlay works just fine. We're gonna end up using the filestack-js package until this is fixed and you expose an onClose() event so we can manage our state.

I've attached a photo showing the issue.

Screen Shot 2021-04-22 at 3 05 58 PM

drewrwilson commented 3 years ago

I'm having the same issue using it in a React app. Is there a workaround?

ehubbell commented 3 years ago

@drewrwilson we ended up using the raw filestack-js package from npm. That package lets you manage the picker state better IMO.

Here's the repo: https://github.com/filestack/filestack-js

And the picker specific documentation: https://filestack.github.io/filestack-js/interfaces/pickeroptions.html

josualeonard commented 3 years ago

I also having this issue, is there something missing with the code?

drewrwilson commented 3 years ago

@josualeonard Yeah, there appears to be a bug in the filestack-react package related to how it appends the file uploader to a container id for <PickerInline /> and <PickerDrop /> (but < PickerOverlay /> seems to work ok). I needed it to be an inline uploader, so I switched to using filestack-js instead of filestack-react, like @ehubbell suggested.

josualeonard commented 3 years ago

Thank you @drewrwilson ! I create my own component to make PickerInLine works. Here's how I do it, just in case anyone stumble upon the same issue:

FilestackPicker.js

/**
 * Filestack-react is having a bug on container id
 * this component here is for making it work
 */
import React, { useEffect } from 'react';
import { client as filestack } from 'filestack-react';

const usePicker = (_ref) => {
  const { apikey } = _ref;
  const _ref$pickerOptions = _ref.pickerOptions;
  const pickerOptions = _ref$pickerOptions === undefined ? {} : _ref$pickerOptions;
  const _ref$clientOptions = _ref.clientOptions;
  const clientOptions = _ref$clientOptions === undefined ? {} : _ref$clientOptions;
  const _ref$onSuccess = _ref.onSuccess;
  // eslint-disable-next-line no-console
  const onSuccess = _ref$onSuccess === undefined ? console.log : _ref$onSuccess;
  const _ref$onError = _ref.onError;
  // eslint-disable-next-line no-console
  const onError = _ref$onError === undefined ? console.error : _ref$onError;

  const _onError = (error) => {
    onError(error);
  };
  const _onSuccess = (result) => {
    onSuccess(result);
  };
  const rootId = 'asset-root';
  const containerId = 'asset-container';
  const picker = filestack.Filestack(apikey, clientOptions).picker({
    ...pickerOptions,
    rootId,
    container: `#${containerId}`,
    onUploadDone: _onSuccess
  });

  useEffect(() => {
    picker.open().then().catch(_onError);
    return () => {
      if (picker) {
        picker.close();
      }
    };
  }, []);
  return {
    containerId
  };
};

const FilestackPicker = (_ref) => {
  const {
    apikey,
    pickerOptions,
    clientOptions,
    onSuccess,
    onError
  } = _ref;

  const _usePicker = usePicker({
    apikey,
    pickerOptions: {
      ...pickerOptions,
      displayMode: filestack.PickerDisplayMode.inline
    },
    clientOptions,
    onSuccess,
    onError
  });
  const { containerId } = _usePicker;
  return <div id={containerId} style={{ height: '500px' }} data-testid="picker-inline" />;
};

export default FilestackPicker;

usage:

<FilestackPicker
  apikey={process.env.REACT_APP_FILESTACK_API_KEY}
  onSuccess={(result) => {
    if (result.filesUploaded.length > 0) {
      setAsset(result.filesUploaded[0]);
    }
  }}
/>

I hope it helps!

soerenmuenster commented 1 year ago

For anyone who is still facing this problem and doesn't want to add their own picker, there is the option to simply define the container with an id in the picker options. Put a div around the picker element with the id defined in the options.

And now the most important thing to consider: Don't use conditional rendering but add it via css in a ternary class. e.g. hidden if it should be hidden.

const options = { container: 'picker-container', }

<div id="picker-container" className={!open ? 'hidden' : 'block'}> <PickerDropPane pickerOptions={options} /> </div>

ladderschool commented 1 year ago

For anyone who is still facing this problem and doesn't want to add their own picker, there is the option to simply define the container with an id in the picker options. Put a div around the picker element with the id defined in the options.

And now the most important thing to consider: Don't use conditional rendering but add it via css in a ternary class. e.g. hidden if it should be hidden.

const options = { container: 'picker-container', }

<div id="picker-container" className={!open ? 'hidden' : 'block'}> <PickerDropPane pickerOptions={options} /> </div>

Sadly this doesn't work for the "PickerInline" component. I'm just going to let those errors happen, doesn't seem to break the functionality.