Smj
Smj

Reputation: 87

React Formik file upload with laravel back-end

I'am using Formik for my forms in React. Everything is okay but for the file input.

The user must be able to upload a CV. The {values.cv} in Formik does indicate that there is a value in the input. However when I send it to my Laravel back-end, I get an empty array.

I want to be able to store the file in my database. Any help would be appreciated.

The Formik file input:

<label className="btn btn-info" htmlFor="cv">
    <input id="cv" name="cv" style={{display: 'none'}} type="file" onChange={(event) => {
     setFieldValue("cv", event.currentTarget.files[0]);
                                    }} />                   
   </label>

The cv input default value is : ' '

This is what is in the {values.cv} Here is the console.log of it

In my Laravel back-end I return the $request and React is logging it. This is what I see then.

cv : []

Here is a picture of my console

Upvotes: 3

Views: 7047

Answers (2)

Derek Adair
Derek Adair

Reputation: 21925

As per this post.

<input id="file" name="file" type="file" onChange={(event) => { setFieldValue("file", event.currentTarget.files[0]); }} />

You can then access all the stuff...

JSON.stringify({ 
  fileName: values.file.name, 
  type: values.file.type,
  size: `${values.file.size} bytes`
}, null, 2);

Upvotes: 4

Linc
Linc

Reputation: 94

Formik doesn't handle file upload, but there's a hack around it provided here https://github.com/jaredpalmer/formik/issues/45

import * as React from 'react';

import { AxiosRequestConfig } from 'axios';
import Image from 'components/Image';
import { Progress } from 'components/Progress';
import ToasterInstance from '../Toast/ToasterInstance';
import { axios } from 'api/axios.config';
import { toApiError } from 'utils/api';

export interface MediaUploadProps {
  id: string;
  slug: string;
  value: string;
  onChange: (field: string, mediaId: string) => void;
}

export interface MediaUploadState {
  progress: number;
  file?: File;
  error?: string;
}

export class MediaUpload extends React.Component<
  MediaUploadProps,
  MediaUploadState
> {
  state: MediaUploadState = { progress: -1 };

  handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    if (!e.target.files) {
      return;
    }
    let file = e.target.files[0];
    this.setState({ file: file });

    let data = new FormData();
    data.append('file', file);

    let config: AxiosRequestConfig = {
      onUploadProgress: (p: any) => {
        this.setState({ progress: Math.round(p.loaded * 100 / p.total) });
      },
    };

    this.setState({ error: undefined, progress: 0 });

    axios.post('/v1/media?slug=' + this.props.slug, data, config).then(
      res => {
        this.setState({ error: undefined, progress: -1 });
        this.props.onChange(this.props.id, res.data.path);
      },
      err => {
        const message = toApiError(err);
        this.setState({ error: message, progress: -1 });
        ToasterInstance.show({
          message,
          iconName: 'danger',
          intent: 'danger',
        });
      }
    );
  }

  handleRemoveImage = () => {
    this.props.onChange(this.props.id, '');
  }

  render() {
    return (
      <div>
        <div>
          {this.props.value !== '' &&
            this.state.progress === -1 &&
            <Image path={this.props.value} size="lg" />}
          <div style={{ maxWidth: 144 }}>
            {this.state.progress > -1 &&
              <Progress percentage={this.state.progress} />}
          </div>
          {this.props.value &&
            <a
              style={{ marginTop: -40 }}
              className="button button--negative button--small button--secondary"
              role="button"
              onClick={this.handleRemoveImage}
            >
              Remove
            </a>}
    </div>
    <div style={{ marginTop: 10 }}>
      <label className="button button--purple button--secondary">
        Upload new picture
        <input
          className="visually-hidden"
          type="file"
          onChange={this.handleFileChange}
        />

      </label>
    </div>

  </div>
);
  }
}

Upvotes: 3

Related Questions