Active-CSS / active-css

The epic event-driven browser language for UI with functionality in one-liner CSS. Over 100 incredible CSS commands for DOM manipulation, ajax, reactive variables, single-page application routing, and lots more. Could CSS be the JavaScript framework of the future?
https://activecss.org
Other
42 stars 7 forks source link

Components should not remove default children until fully loaded #246

Closed bob2517-whiteline closed 2 years ago

bob2517-whiteline commented 2 years ago

Take this scenario:

<address-data data-id="123"></address-data>

Let's say you want to get address data from the server whenever this tag is drawn. And the database that you need to get the data from is not under your control, and it's a bit laggy. So you need to display a "loading data" graphic or text while the component is loading. You've found a fancy CSS animation that you want to use.

So you try and do it like this:

<address-data data-id="123">
    <div class="myFancyCSSLoadingAnimation"></div>
</address-data>

Currently in ACSS, children of components (like the div above) can be output using the {$CHILDREN} variable anywhere in the HTML contents of a component. So whatever you put inside component tags, such as the wait graphic above, these can be output again in a different place when the component is rendered, using the {$CHILDREN} variable. This is great. I've not personally found an actual use for it yet, but it works anyway, and I can think of a couple of scenarios where it could be useful.

But there are two things that the core currently does, that stops this incredible wait graphic code from behaving as you would expect.

1) All children of components currently always draw UNDERNEATH the component HTML if the {$CHILDREN} is not used. This was a bit of a random thing to do, but I thought it was a good idea at the time. I didn't have a use case for it...

2) All children of components disappear as soon as the component STARTS to load. So as soon as things start to get loaded using the new component html() option using ajax internally, the children disappear, and only reappear when the component has loaded. So the wait graphic example above disappears as soon as the ajax starts, rather than the expected behaviour of disappearing when the component finally renders.

So I'm going to make a potentially breaking change which will go live with 2.10.0.

Here's what's going to happen:

To put a loading graphic, or whatever, into a component that is going to take a while to load (like a second or two), do this:

<address-data data-id="123">
    <div class="waitingAnimation"></div>
</address-data>

The children of the component will then disappear when the component is rendering, after all ajax calls have completed, and be replaced with the proper component content.

The children will actually disappear - this will be new. The children of components, like the wait graphic above, will NOT render again when the component finally renders, unless the {$CHILDREN} variable is specifically specified.

This is the simplest, and most obvious solution to having components that can have loading indicators that disappear when the component is finally loaded.

You can still display the initial children of the component when the component renders. Just use the {$CHILDREN} variable in the component HTML - put it where you want. Use it multiple times in the HTML if you need to. That's the potentially breaking change - the necessity to use {$CHILDREN} to render the initial component child nodes within the finished rendered component.

I've already got the code written for this, and all looks good so far, but I need to run more tests.

bob2517-whiteline commented 2 years ago

Just out of interest, if you happened to be using a Laravel view as your component on the server, the ACSS needed could just look like this. This would be all that is needed from ACSS to render your blade component whenever the custom element was drawn on the page - something like this anyway (assuming you didn't want any event handlings):

@component address-data html("/fetch-address" post post-pars(id={@data-id}) html) {}
bob2517-whiteline commented 2 years ago

Note - the event to run BEFORE a component starts to load is the draw event. You would use that if you wanted to run an event before anything else starts happening - like trigger a JavaScript progress indicator or something like that (which you would later remove in the componentOpen event inside the component itself.)

Eg.

address-data:draw {
    .. trigger something before the component starts loading.
}

@component address-data html("/fetch-address" post post-pars(id={@data-id}) html) {
    &:componentOpen {
        ... remove it now that the component has loaded.
    }
}

The core does this already.

bob2517 commented 2 years ago

Now on the latest 2.10.0 branch.