How to upload an Image while creating a Page in a Section Plugin

Hi all,
i am doing a Section-Plugin, which instantly creates a Message-Page from Site-Level.
That already works.
Beside other fields, i need to add an Image-Upload, which upload an image into the created page and assign it to a files-field. Unfortenetly i don’t know how to add the endpoints-object to the k-files-field. I can’t really find examples/infos for that.

Would be nice, if someone can point me to how that has to be done.
Here is a simplified example of the plugin/code.

grafik
grafik

export default {
  data() {
    return {
      headline: '',
      title: '',
      files: [],
    }
  },
  created() {
    this.load().then(response => {
      this.headline = response.headline;
    });
  },
  methods: {
    create() {
      let content = {
        title: this.title
      };
      this.$api
        .post('pages/messages/children', { slug: this.title, template: 'message', content: content })
        .then(response => {
            console.log('page created')
        })
        .catch(error => {
          console.log('error', error)
        });
    },
  }
};
<template>
  <section class="k-links-section">
    <fieldset class="k-fieldset">
      <k-grid>
        <k-column width="1/1">
          <k-headline-field :label="headline" numbered="true" />
        </k-column>
        <k-column width="1/1">
          <k-text-field v-model="title" name="title" label="Title/Slug" />
        </k-column>
        <k-column width="1/1">
          <k-files-field v-model="files" :max="1" name="files" label="Files"
          :uploads="{'accept':'*'}"
          type="files"
          size="large"
          help="Helptext"
          layout="cards"
          />
        </k-column>
        <k-column width="1/4">
          <k-button class="btn-create" icon="add" theme="none" @click="create()" type="submit">Create</k-button>
        </k-column>
      </k-grid>
    </fieldset>
  </section>
</template>

Thx!!

1 Like

Don’t know why you are getting this error. But in any case, I think you need a custom endpoint if you want to create a page and then upload files as well. The existing endpoints don’t do two things at a time.

The problem here is probably that the files field tries to upload the file to a non-existing page. So I’m wondering if this is the right way to go about this.

Unfortenetly i have no idea, how to add an endpoint in general. :man_shrugging:
I have never used k-files-field before.
Has the endpoints to be a route by php or can they all be done by js: this.$api?

Don’t know why you are getting this error.

Could of curse be a problem, that the section-plugin is on Site-Level.
The error already occurs, when i try to select or upload a file.

The problem here is probably that the files field tries to upload the file to a non-existing page. So I’m wondering if this is the right way to go about this.

That’s for sure correct. same prob: i do not yet know, what to add in the endpoints-object.
And you are also right, that the page does not exists before the image is selected (and uploaded)
In the original version of this plugin, i have already a method to add data i.e. to a blocks field, after creation of the page, because it was not possible, to add that while creation.
maybe i can copy and assign the image data in that method too. dont know.

do you know any plugin, where i can have a look or an example to get a glimmer?

I had a closer look at the files field. It calls an upload API route that is part of the files field. This endpoint in turn calls an upload() method in the upload mixin, which then again call the $api->upload() method.

The problem is that the field is bound to an object model (site or page object) which probably doesn’t exist in the context where you are using the field and which is why this.endpoints is undefined. My guess is that you would have to create a custom upload with your own API endpoints to make this work. In fact, IMO you don’t need a files field but an upload input/drop zone. And then some API endpoint to which you send all your data, which then handles first the page creation and then saving the file to this page. So much for theory.

Maybe have a look at the source code of the field for a better understanding (download the source kirby repo instead of the kirby folder that comes with the Starterkit, because it has the uncompiled source code).

I just remembered that there is this showcase plugin which could probably help you: GitHub - pwaldhauer/kirby-quick-add: Kirby Quick Add Panel Section

that were very good tips!
it already works with dropzone/upload by drag a file and upload it after page-creation and assign it to the corresponding img-field.
unfortunately the upload-select-handler directly calls the upload-method on select a file, but as said, that is not possible, before the page is created. i guess i have to to add independet markup for the file-select part and add them to the uploader by myself.

Thank you very much for pointing me.

below the so far solution, in case anyone needs it.
like said, we cannot use k-files-field, nor the select of k-upload, because it would instantly upload the file, but there is no page created yet, so that won’t work.
We have added a plain hidden input-file, and trigger them by click on the dropzone or add-button.
onDrop and onSelect we store the files and upload them via uploader.drop after creation of the page.

Important note:
To assign that file to the files-field of the new page, we have to wait for the onUploadSuccess and use the filename of the second argument. that can be slightly different, then the filename on select, because kirby can make some rename operations i.e. space to dash

<template>
    <section class="createpage-section">
        <fieldset class="k-fieldset">
            <k-grid>
                <k-column width="1/1">
                    <k-headline-field :label="headline" numbered="true" />
                </k-column>
                <k-column width="1/1">
                    <header class="k-field-header">
                        <label class="k-field-label">Image</label>
                        <k-button icon="add" @click="select">Add</k-button>
                    </header>
                    <k-dropzone @drop="onDrop">
                        <button data-layout="cards" type="button" class="k-empty" @click="select">
                            <span aria-hidden="true" class="k-icon k-icon-image">
                                <svg viewBox="0 0 16 16">
                                    <use xlink:href="#icon-image"></use>
                                </svg>
                            </span>
                            <p>{{ dropzoneText }}</p>
                        </button>
                    </k-dropzone>
                    <input ref="fileselect" type="file" style="display: none;" @change="onSelect" accept="image/*" />
                    <k-upload ref="uploader" @success="onUploadSuccess" />
                </k-column>
                <k-column width="1/4">
                    <k-button class="btn-create" icon="add" theme="none" @click="create(false)" type="submit">Create
                        Page
                    </k-button>
                </k-column>
            </k-grid>
        </fieldset>
    </section>
</template>
export default {
    data() {
        return {
            headline: '',
            title: 'test-message',
            dropzoneText: 'No Files selected',
            pagePath: null,
            files: null
        }
    },

    created() {
        this.load()
            .then(response => {
                this.headline = response.headline;
            });
    },

    methods: {
        create() {
            this.$api.post('pages/messages/children', {
                slug: this.$helper.slug(this.title),
                template: 'message',
                content: {
                    title: this.title
                }
            }).then(data => {
                this.pagePath = data.id.replace(/\//g, '+');
                if (this.files) {
                    this.upload();
                }
            });
        },

        select() {
            this.$refs.fileselect.click();
        },

        upload() {
            let url = this.$urls.api + '/' + this.$api.pages.url(this.pagePath, 'files')
            this.$refs.uploader.drop(this.files, {
                url: url,
                multiple: true,
            })
        },

        onSelect(e) {
            this.files = e.target.files;
            this.dropzoneText = this.files[0].name;
        },

        onDrop(files) {
            this.files = files;
            this.dropzoneText = this.files[0].name;
        },

        onUploadSuccess(files, data) {
            this.files = null;
            this.dropzoneText = 'No Files selected';
            this.$api.pages.update(this.pagePath, {
                img: data[0].filename
            })
        }
    }
};

This example does not yet take care of every error or multiple file selection and it uses hardcoded title, blueprint and paths.
Thanks again for your support @texnixe