I’m working with LiveView.assign_async
, which provides :ok
, :failed
, and :loading
statuses. I think it would benefit from adding a :not_asked
status.
The assign I’m working with, which I’ll just call state
for now, only gets triggered after a user action. So at mount/3
, the state
is nil
.
In render
, I have to wrap any checks on state
, like state.ok?
or state.loading
, with a nil
check first. Here’s what I’ve tried:
Checking for state = nil
<div :if={@state[:ok?]}>Not asked, the state is nil</div>
This works fine, but when state
switches to AsyncResult.loading
, it throws an Access error:
(UndefinedFunctionError) function Phoenix.LiveView.AsyncResult.fetch/2 is undefined (Phoenix.LiveView.AsyncResult does not implement the Access behaviour)
Workaround 1: Wrapping Everything
One option is to wrap every state
check inside a nil
check:
<div :if={!is_nil(state)}>
<div :if={state.ok?}>Success on showing state</div>
<div :if={state.loading}>Hold on, loading...</div>
<div :if={state.failed}>There was an error!</div>
</div>
This works but starts to get cumbersome when state
needs to be checked in multiple places across the page.
Workaround 2: Initialize with :not_asked
The other approach is to initialize state
as AsyncResult.failed(%AsyncResult{}, :not_asked)
:
<div :if={state.ok?}>Success on showing state</div>
<div :if={state.loading}>Hold on, loading...</div>
But when handling failures, you need to differentiate between actual errors and the :not_asked
state:
<div :if={state.failed}>There was an error. Wait! It might just be that it wasn’t asked yet.</div>
<div :if={state.failed != :not_asked}>There was a real error</div>
<div :if={state.failed == :not_asked}>Press here to load</div>
Suggested Improvement: Add :not_asked
Status
I think it would be helpful to add a :not_asked
status, so you can handle these cases more cleanly. One would need to initiate the assign, but after that, it would be easier to work with.
<div :if={state.ok?}>Success on showing state</div>
<div :if={state.loading}>Hold on, loading...</div>
<div :if={state.failed}>There was an error, a real one.</div>
<div :if={state.not_asked}>Press here to load</div>
Adding a :not_asked
status simplifies the logic and removes the need for repetitive nil
checks. It would make the state handling in LiveView.assign_async
cleaner, especially in situations where user actions trigger the state change.
A PR could look like this: