krayin / laravel-crm

Free & Opensource Laravel CRM solution for SMEs and Enterprises for complete customer lifecycle management.
https://krayincrm.com
Open Software License 3.0
11.58k stars 796 forks source link

Image not being passed to params in form component #1680

Closed aldoemir closed 1 month ago

aldoemir commented 1 month ago

Bug report

Image not being passed to params in form component


Issue Description

When using the x-admin::media.images component the content of it won't be passed to params of updateOrCreate method. I don't think the vee-validate field is implemented in media.images component.,

Preconditions

Please provide as detailed information about your environment as possible.

1. framework Version: 2.0
2. Commit id: a96275c

Steps to reproduce

It is important to provide a set of clear steps to reproduce this bug.If relevant please include code samples.

...
<x-admin::form
      v-slot="{ meta, errors, handleSubmit }"
      as="div"
      ref="modalForm"
  >
      <form @submit="handleSubmit($event, updateOrCreate)">
          {!! view_render_event('admin.settings.makes.index.create_form_controls.before') !!}

          {!! view_render_event('admin.settings.makes.index.form.modal.before') !!}

          <x-admin::modal ref="makeUpdateAndCreateModal">
              <!-- Modal Header -->
              <x-slot:header>
                  <p class="text-lg font-bold text-gray-800 dark:text-white">
                      @{{
                          selectedMake
                          ? "@lang('car::app.settings.makes.index.edit.title')"
                          : "@lang('car::app.settings.makes.index.create.title')"
                      }}
                  </p>
              </x-slot>

              <!-- Modal Content -->
              <x-slot:content>
                  {!! view_render_event('admin.settings.makes.index.content.before') !!}

                  <x-admin::form.control-group.control
                      type="hidden"
                      name="id"
                  />

                  {!! view_render_event('admin.settings.makes.index.form.form_controls.logo.before') !!}

                   <!-- Logo -->
                  <x-admin::form.control-group>
                      <x-admin::form.control-group.label>
                          @lang('car::app.settings.makes.index.create.logo')
                      </x-admin::form.control-group.label>

                      <x-admin::media.images
                          name="logo"
                      />

                      <x-admin::form.control-group.error control-name="logo" />
                  </x-admin::form.control-group>

                  {!! view_render_event('admin.settings.makes.index.form.form_controls.logo.after') !!}

                  {!! view_render_event('admin.settings.makes.index.form.form_controls.name.before') !!}

                  <!-- Name -->
                  <x-admin::form.control-group>
                      <x-admin::form.control-group.label class="required">
                          @lang('car::app.settings.makes.index.create.name')
                      </x-admin::form.control-group.label>

                      <x-admin::form.control-group.control
                          type="text"
                          id="name"
                          name="name"
                          rules="required"
                          :label="trans('car::app.settings.makes.index.create.name')"
                          :placeholder="trans('car::app.settings.makes.index.create.name')"
                      />

                      <x-admin::form.control-group.error control-name="name" />
                  </x-admin::form.control-group>

                  {!! view_render_event('admin.settings.makes.index.form.form_controls.name.after') !!}
              </x-slot>

              <!-- Modal Footer -->
              <x-slot:footer>
                  {!! view_render_event('admin.settings.makes.index.form.form_controls.save_button.before') !!}

                  <!-- Save Button -->
                  <x-admin::button
                      button-type="submit"
                      class="justify-center primary-button"
                      :title="trans('car::app.settings.makes.index.create.save-btn')"
                      ::loading="isProcessing"
                      ::disabled="isProcessing"
                  />

                  {!! view_render_event('admin.settings.makes.index.form.form_controls.save_button.after') !!}
              </x-slot>
          </x-admin::modal>

          {!! view_render_event('admin.settings.makes.index.form.modal.after') !!}
      </form>
  </x-admin::form>

  {!! view_render_event('admin.settings.makes.index.form.after') !!}
  </script>

  <script type="module">
  app.component('v-make-settings', {
      template: '#make-settings-template',

      data() {
          return {
              isProcessing: false,
          };
      },

      computed: {
          gridsCount() {
              let count = this.$refs.datagrid.available.columns.length;

              if (this.$refs.datagrid.available.actions.length) {
                  ++count;
              }

              if (this.$refs.datagrid.available.massActions.length) {
                  ++count;
              }

              return count;
          },
      },

      methods: {
          openModal() {
              this.$refs.makeUpdateAndCreateModal.toggle();
          },

          updateOrCreate(params, {
              resetForm,
              setErrors
          }) {
              console.log(params);

              this.isProcessing = true;

              this.$axios.post(params.id ? `{{ route('car.settings.makes.update', '') }}/${params.id}` :
                  "{{ route('car.settings.makes.store') }}", {
                      ...params,
                      _method: params.id ? 'put' : 'post'
                  }, {
                      headers: {
                          'Content-Type': 'multipart/form-data',
                      }
                  }).then(response => {
                  this.isProcessing = false;

                  this.$refs.makeUpdateAndCreateModal.toggle();

                  this.$emitter.emit('add-flash', {
                      type: 'success',
                      message: response.data.message
                  });

                  this.$refs.datagrid.get();

                  resetForm();
              }).catch(error => {
                  this.isProcessing = false;

                  if (error.response.status === 422) {
                      setErrors(error.response.data.errors);
                  }
              });
          },

          editModal(url) {
              this.$axios.get(url)
                  .then(response => {
                      this.$refs.modalForm.setValues(response.data.data);

                      this.$refs.makeUpdateAndCreateModal.toggle();
                  })
                  .catch(error => {});
          },
      },
  });
  </script>
1. Create an `x-admin::form`
2. Pass `x-admin::media.images` into it

Expected result

Image to be passed to params

Actual result

Image never shows up

suraj-webkul commented 1 month ago

Hello, @aldoemir,

The updateOrCreate method, which is passed as an argument from the form component, is responsible for handling input fields:

<x-admin::form.control-group.control
   type="text"
   id="name"
   name="name"
/>

or the Vue component:

<v-field></v-field>

However, for the image component, since the input field is created using native HTML, you will need to utilize JavaScript's native FormData in combination with the $refs method. This will allow you to capture all input fields, including those in the image component, as shown below:

<x-admin::form
    v-slot="{ meta, values, errors, handleSubmit }"
    as="div"
>
    <form 
        @submit="handleSubmit($event, updateOrCreate)"
        ref="form"
    ></form>
</x-admin::form>

In your JavaScript method:

updateOrCreate(params, { resetForm, setErrors }) {
    let formData = new FormData(this.$refs.form);
}

Using FormData, you’ll be able to collect data from all input fields, including the image component's input field.

Best regards,
(Suraj)

aldoemir commented 1 month ago

It worked! But when I'm opening the modal the logo doesn't show up. Here's the meta when I open the edit modal:

{
  "initialValues": {
    "id": 16,
    "name": "asdfg"
  },
  "touched": false,
  "pending": false,
  "valid": true,
  "dirty": true
}

As you can see, the logo is missing.

suraj-webkul commented 1 month ago

Hello, @aldoemir,

To display the uploaded image, you need to pass additional props to the image Blade component. Here's an example:

<x-admin::form.control-group>
    <x-admin::media.images
        name="image"
        ::uploaded-images="pathOfImage ? [['id' => 'image', 'url' => pathOfImage]] : []"
    />
</x-admin::form.control-group>

In this example, :: (double colon) indicates that uploaded-images is accepting a JavaScript variable, whereas : (single colon) means it is expecting a PHP variable.

For reference, you can review the code structure in the following file:packages/Webkul/Admin/src/Resources/views/settings/users/index.blade.php

Best regards,
(Suraj)

devansh-webkul commented 1 month ago

Thank you for reaching out. It looks like your request is not an issue report. For discussions, questions, or general support, we encourage you to use the Krayin Forum. The forum is the best place for such queries, and you'll be able to connect with other community members and get the help you need.

Please reserve the GitHub issue tracker for reporting bugs and issues with the codebase. This helps us keep the issue tracker focused and ensures that problems are addressed promptly.

Thank you for your understanding!