ux icon indicating copy to clipboard operation
ux copied to clipboard

[LiveComponent] `data-loading` attribute doesn't hide on AJAX complete when class is provided

Open allejo opened this issue 2 years ago • 4 comments

On page load, an element can have both the data-loading attribute and a class. When an AJAX event is sent, the element correctly becomes visible to the user. However, when the AJAX event completes and the data-loading element would typically hide, it doesn't if it has a class attribute.

<div {{ init_live_component(this) }}>
    <button class="shopping-cart-btn"
        aria-label="{{ this.description }}"
        data-action="live#action"
        data-action-name="updateCart"
        data-loading="addAttribute(disabled)"
    >
        <span data-loading="show" class="spin"> {# <= HERE #}
            <i aria-hidden="true" class="bi-arrow-repeat"></i>
        </span>
        <span data-loading="hide">
            <i aria-hidden="true" class="{{ this.icon }}"></i>
        </span>
    </button>
</div>

The way I was able to get around this problem is by separating the data-loading and class attributes into separate elements.

<div {{ init_live_component(this) }}>
    <button class="shopping-cart-btn"
        aria-label="{{ this.description }}"
        data-action="live#action"
        data-action-name="updateCart"
        data-loading="addAttribute(disabled)"
    >
        <span data-loading="show"> {# <= HERE #}
            <span class="spin">
                <i aria-hidden="true" class="bi-arrow-repeat"></i>
            </span>
        </span>
        <span data-loading="hide">
            <i aria-hidden="true" class="{{ this.icon }}"></i>
        </span>
    </button>
</div>

I would expect that if the attribute combination works correctly on page load and AJAX start, then it would also work on AJAX complete.

allejo avatar Jan 21 '22 07:01 allejo

I tried to reproduce this error in tests and in the live-demo but unfortunatly (?) i did not manage get this error.

Data-Loading show or hide does work for me with and without additional classes on the element. What i tried was

    <small data-loading="show" class="TEST">SHOW ME</small>
    <small data-loading="hide" class="TEST">HIDE ME</small>
    <small data-loading="show">SHOW ME</small>
    <small data-loading="hide">HIDE ME</small>

Does your class "spin" maybe add some css like a display inline or something ? The "hide" is done by css

[data-loading=""], [data-loading="show"], [data-loading="delay|show"] {
    display: none;
}

BeyerJC avatar Jan 24 '22 10:01 BeyerJC

Ah you are right, my .spin class does indeed have a display: inline-block.

allejo avatar Jan 24 '22 18:01 allejo

Hm would it be reasonable to add !Important to the style to force the display none? Or set it as style attribute equally to the display lnline part.

I feel like it wouldnt be a clean solution. But maybe @weaverryan has an idea. At least we could add a Note in the docs

BeyerJC avatar Jan 24 '22 18:01 BeyerJC

Hmm. I'm not sure about the best solution here! My initial reaction is that our CSS should add !important on it. So:

[data-loading=""], [data-loading="show"], [data-loading="delay|show"] {
    display: none !important;
}

Adding!important is usually not something I love doing, however. And, I double-checked Livewire, and they (somehow) have similar CSS to us (no !important) and I can't find any mention of problems over there.

In addition, or possibly "instead" of doing that, we should probably do the hiding with a style attribute as mentioned. Well, to be clear: that IS how it works. Once you, for example, make your first Ajax request, hiding & showing is done via the style attribute. The CSS only exists to try to hide elements correctly, on page-load, before any JS executes. To fix the situation we could, on connect() of live controller, parse the components for data-loading attributes and "process" those. For example, if we find an element with data-loader="show", we would hide the element (exactly like we would once an ajax request finishes). This would mean that:

A) On initial page load, the above CSS still immediately hides those elements. But... if it doesn't work for some reason like this, it is more of a minor problem. B) very shortly after page load, the live controller JS correctly processes all the data-loading attributes so that any elements that SHOULD be hidden, have display: none style.

If someone would like to work on that, it would be appreciated :)

Cheers!

weaverryan avatar Jan 28 '22 01:01 weaverryan

Thank you for this issue. There has not been a lot of activity here for a while. Has this been resolved?

carsonbot avatar Apr 26 '24 12:04 carsonbot