mdbootstrap / mdb-ui-kit

Bootstrap 5 & Material Design UI KIT
https://mdbootstrap.com/docs/standard/
Other
24.2k stars 3.53k forks source link

Laravel Livewire breaks forms #1432

Closed smares closed 3 years ago

smares commented 3 years ago

First of all, I am a paying customer and tried to post this on your official support forum a few minutes ago only to get a HTTP 406 by your nginx upon submission. Also, please update your version picker in the support forum as the latest version displayed there is 3.2.0.

MDBootstrap 5 3.3.0 forms do not play well with Laravel Livewire. As soon as you type in something into an input element that is wired to a Livewire component property, once the input loses focus, the label moves back inside the input as if the input was empty. If you click on the input again, the label moves to the top and stays there, or you get a "Cannot read property 'style' of null" error in the console. (Could be a race condition, either one of the outcomes is possible.)

Another problem I have is with validation. If a validation error occurs, the <div class="invalid-feedback"> becomes visible, the label of the input turns red, but it's sitting inside the input behind the input value and the input loses its border.

Here's a demo to play with: https://laravelplayground.com/#/snippets/b790c5e1-6bc7-4759-8cd7-5f074e2d6a6c

To reproduce the issue no. 1, just type in anything in the input and move the focus away from the input. To reproduce the issue no. 2, simply click the button without typing anything, or type in something that is not an e-mail address then submit, or type in an e-mail address with less than 100 characters then submit.

smares commented 3 years ago

Here's another demo showing that the problem is caused by MDB and not by Bootstrap. Bootstrap 5 floating labels work fine with Laravel Livewire: https://laravelplayground.com/#/snippets/62ff0b12-70be-4869-bb35-3f280fa35aa1

catchmareck commented 3 years ago

Hi @smares, I'm from MDB Backend/DevOps team. I'm sorry for such a late response. Regarding the 406 error, we are really sorry for the inconvenience. Recently, we have updated our firewall rules, and apparently, for some reason, you were recognized as a potential threat and got blocked. We are trying to fine-tune the rules so that the customers wouldn't be affected but at the same time attackers couldn't do any harm. Your issue is taken into account and we'll try to modify our firewall settings so that such cases won't happen again.

As for your problem with the MDB package - the Issue is forwarded to the Frontend team and will be handled ASAP.

smolenski-mikolaj commented 3 years ago

Hi there @smares , I'm from the MDB Frontend Team. The issue was already posted in our forum channel and our developers opened a new ticket in our board. For this moment, we can guarantee that our UI KIT is integrated with Laravel framework and works as expected. We even prepared a dedicated Admin Dashboard with Laravel. However, in this case the problem is closely related to the Livewire full-stack framework, which we still have to test and integrate with our UI KIT.

smares commented 3 years ago

OK, I am closing this issue then.

datlechin commented 1 year ago

@smolenski-mikolaj after 2years, the issue still be there

smares commented 1 year ago

It's not much they can do about it as Livewire replaces the DOM element with a new one, so it's up to you to de-init the old component and init the new component. You can do something like this:

  const updateMdbInputsOnLivewireUpdate = () => {
    const dispose = element => {
      try {
        mdb.Input.getInstance(element)?.dispose()
      } catch (e) {
      }
    }

    const init = element => {
      try {
        const instance = mdb.Input.getInstance(element) ?? new mdb.Input(element)
        instance.update()
      } catch (e) {
      }
    }

    Livewire.hook('element.updating', fromElement => {
      if (fromElement.classList.contains('form-outline')) {
        dispose(fromElement)
      } else {
        for (const inputElement of fromElement.querySelectorAll('.form-outline')) {
          dispose(inputElement)
        }
      }
    })

    Livewire.hook('element.updated', element => {
      requestAnimationFrame(() => {
        if (element.classList.contains('form-outline')) {
          init(element)
        } else {
          for (const inputElement of element.querySelectorAll('.form-outline')) {
            init(inputElement)
          }
        }
      })
    })
  }

And simply call updateMdbInputsOnLivewireUpdate() once on page load.

datlechin commented 1 year ago

@smares thank you