Last active
May 21, 2023 15:28
-
-
Save conradfr/a2f072edfb889bfd169bed22421e2ac6 to your computer and use it in GitHub Desktop.
LiveView Boostrap v5 toast component
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
One possible implementation of Bootstrap toasts. | |
Using a Live Component. | |
Note: | |
If you ask for a toast to show and navigate to another LiveView the component will be unmounted and your toast will not be displayed. | |
For a solution using a separate LiveView check: https://gist.github.com/conradfr/50c250ea5fddcf12979f6ca5282a3af1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule BsToastComponent do | |
use MyAppWeb, :live_component | |
alias Phoenix.LiveView.JS | |
def render(assigns) do | |
~H""" | |
<div | |
id={@id} | |
phx-hook="BsToast" | |
phx-update="stream" | |
class="toast-container position-absolute end-0 p-3" | |
> | |
<div | |
:for={{id, toast} <- @streams.toasts} | |
id={id} | |
role="alert" | |
aria-live="assertive" | |
aria-atomic="true" | |
class={"toast text-white #{if toast.type == :success, do: "bg-success"}#{if toast.type == :error, do: "bg-warning"}"} | |
> | |
<div class="d-flex justify-content-center align-items-center p-3"> | |
<div class="toast-icon"> | |
<i class={"bi #{if toast.type == :success, do: "bi-check-circle-fill"}#{if toast.type == :error, do: "bi-x-circle-fill"}"}> | |
</i> | |
</div> | |
<div class="toast-body flex-fill py-0 text-center align-middle"> | |
<%= toast.message %> | |
</div> | |
</div> | |
</div> | |
</div> | |
""" | |
end | |
@impl true | |
def mount(socket) do | |
{:ok, | |
socket | |
|> stream(:toasts, [])} | |
end | |
@impl true | |
def update(assigns, socket) when is_map_key(assigns, :toast) == false do | |
{:ok, assign(socket, :id, assigns.id)} | |
end | |
@impl true | |
def update(assigns, socket) do | |
with %Toast{} = toast <- Map.get(assigns, :toast) do | |
{:ok, | |
socket | |
|> stream_insert(:toasts, toast) | |
|> push_event("show_toast", %{id: "toasts-" <> toast.id})} | |
else | |
_ -> {:ok, socket} | |
end | |
end | |
@impl true | |
def handle_event("toast_closed", %{"id" => id} = _params, socket) do | |
{:noreply, stream_delete_by_dom_id(socket, :toasts, id)} | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const TOAST_DURATION = 3500; | |
const BsToastHook = { | |
mounted() { | |
this.handleEvent('show_toast', ({ id }) => { | |
const toastElem = document.getElementById(id); | |
if (toastElem) { | |
const toast = new bootstrap.Toast(toastElem, {delay: TOAST_DURATION}); | |
toast.show(); | |
setTimeout( | |
() => { | |
toast.hide(); | |
this.pushEventTo(this.el, 'toast_closed', { id }); | |
}, | |
TOAST_DURATION + 500 | |
); | |
} | |
}); | |
} | |
}; | |
export default BsToastHook; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
toast = Toast.new("Great success !") | |
send_update(BsToastComponent, id: "bs-toast", toast: toast) | |
toast = Toast.new("Still great success !", :success) | |
send_update(BsToastComponent, id: "bs-toast", toast: toast) | |
toast = Toast.new("An error occurred", :error) | |
send_update(BsToastComponent, id: "bs-toast", toast: toast) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Toast do | |
use Ecto.Schema | |
@primary_key false | |
embedded_schema do | |
field(:id, :string) | |
field(:message, :string) | |
field(:type, Ecto.Enum, values: [:success, :error]) | |
end | |
def new(message, type \\ :success) when is_binary(message) do | |
%Toast{ | |
id: System.unique_integer([:positive]) |> Integer.to_string(), | |
message: message, | |
type: type | |
} | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment