最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Strapi - How can I upload files and create new model entry at the same time? - Stack Overflow

programmeradmin0浏览0评论

In my app, I wish to do just like in the admin panel. I have a form that have other datas + files and I want to create everything at once. How can I do that if I don't know the RefID since the new entry is not yet created. I have tried alot of things and so far nothing works. Here is code example :

Form :

 jobsForm = this.fb.group({
    nom: [null],
    date: [null],
    address_chargement: [null],
    address_dechargement: [null],
    client: [null],
    pleted: [false],
    status: ['waiting'],
    ment_user: [null],
    ment_admin: [null],
    files: [null],
});

Form is dispatched to NGRX Store create action which call my service as follow :

public createJob = (payload: IJob): Observable<IJob>  => {
    const data = new FormData();
    Object.entries(payload).forEach(([key, value]) => {
        data.append(key, value);
    });
    return this.http.post<IJob>(`${this.env.backendUrl}/jobs`, data);
}

I get errors such as :

[2019-06-16T20:10:03.573Z] error Error: SQLITE_ERROR: table jobs has no column named fields

Or it just does not upload.

In my app, I wish to do just like in the admin panel. I have a form that have other datas + files and I want to create everything at once. How can I do that if I don't know the RefID since the new entry is not yet created. I have tried alot of things and so far nothing works. Here is code example :

Form :

 jobsForm = this.fb.group({
    nom: [null],
    date: [null],
    address_chargement: [null],
    address_dechargement: [null],
    client: [null],
    pleted: [false],
    status: ['waiting'],
    ment_user: [null],
    ment_admin: [null],
    files: [null],
});

Form is dispatched to NGRX Store create action which call my service as follow :

public createJob = (payload: IJob): Observable<IJob>  => {
    const data = new FormData();
    Object.entries(payload).forEach(([key, value]) => {
        data.append(key, value);
    });
    return this.http.post<IJob>(`${this.env.backendUrl}/jobs`, data);
}

I get errors such as :

[2019-06-16T20:10:03.573Z] error Error: SQLITE_ERROR: table jobs has no column named fields

Or it just does not upload.

Share Improve this question asked Jun 16, 2019 at 20:39 Jean-Philippe DufourJean-Philippe Dufour 1514 silver badges15 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 4

This is possible to do that.

By default it's not, you will have to do some updates in your controllers / services.

The content manager have this ability to manage entry creation and file upload in the same request. So let's copy this logic in your create action.

Note: you will have to send the request with a FormData - was not this type of request before.

Here is the controller function that create entry https://github./strapi/strapi/blob/master/packages/strapi-plugin-content-manager/controllers/ContentManager.js#L61

Here is the service function that create and upload the files https://github./strapi/strapi/blob/master/packages/strapi-plugin-content-manager/services/ContentManager.js#L63

First you will have to create a new service function named addAndUpload.

async addAndUpload(ctx) {
  // Get form data
  let values = ctx.request.body;

  // Silent recursive parser.
  const parser = value => {
    try {
      value = JSON.parse(value);
    } catch (e) {
      // Silent.
    }

    return _.isArray(value) ? value.map(obj => parser(obj)) : value;
  };

  // Get files
  const files = values.files;

  // Get entry data
  values = Object.keys(values.fields).reduce((acc, current) => {
    acc[current] = parser(values.fields[current]);

    return acc;
  }, {});

  // Create the entry without files
  const entry = await strapi.api.job.services.add(values)

  // Then, request plugin upload.
  if (Object.keys(files).length > 0) {
    // Upload new files and attach them to this entity.
    // Here `job` have to be the model name
    await strapi.plugins.upload.services.upload.uploadToEntity(
      {
        id: entry.id || entry._id,
        model: 'job',
      },
      files
    );
  }

  return strapi.api.job.services.job.findOne({
    id: entry.id || entry._id,
  });
}

And in your create controller function your will have to call strapi.api.job.services.addAndUpload(ctx) instead of the add function.

I think itsn't possible make like that. I suggest break create Job proccess to two steps:

  1. Create File -> POST /upload.
  2. Create Job with id from FileResponse -> POST /job.

SQLITE_ERROR inform you that Job model doesn't have fields, becouse Job models accepts refId to File.

You can use switchMap to merge two Observable.

File Upload

You can also add files during your entry creation.

For example, given the Restaurant model attributes:

path: ./src/api/restaurant/content-types/restaurant/schema.json


{
  // ...
  "attributes": {
    "name": {
      "type": "string"
    },
    "cover": {
      "type": "media",
      "multiple": false,
    }
  }
  // ...
}
<form>
  <!-- Can be multiple files if you setup "collection" instead of "model" -->
  <input type="text" name="name" />
  <input type="file" name="cover" />
  <input type="submit" value="Submit" />
</form>

<script type="text/javascript">
  const form = document.querySelector('form');

  form.addEventListener('submit', async (e) => {
    e.preventDefault();

    const data = {};
    const formData = new FormData();

    form.elements
      .forEach(({ name, type, value, files, ...element }) => {
        if (!['submit', 'file'].includes(type)) {
          data[name] = value;
        } else if (type === 'file') {
          files.forEach((file) => {
            formData.append(`files.${name}`, file, file.name);
          });
        }
      });

    formData.append('data', JSON.stringify(data));

    await fetch('/api/restaurants', {
      method: 'post',
      body: formData
    });
  });
</script>

Your entry data has to be contained in a data key and you need to JSON.stringify this object. The keys for files need to be prefixed with files (e.g. for a cover attribute: files.cover).

NOTE: You have to send FormData in your request body.

Reference - strapi-v4 doc

发布评论

评论列表(0)

  1. 暂无评论