### Install UpChunk JS Library Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/external-uploads.md Install the UpChunk library using npm for chunked HTTP uploads. ```shell $ npm install --prefix assets --save @mux/upchunk ``` -------------------------------- ### LiveSocket JavaScript Setup Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/introduction/welcome.md Initializes the LiveSocket connection in the application's JavaScript entry point, enabling LiveView functionality. ```javascript import {Socket} from "phoenix" import {LiveSocket} from "phoenix_live_view" let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content") let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}}) liveSocket.connect() ``` -------------------------------- ### Run all end-to-end tests Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/test/e2e/README.md Execute all end-to-end tests using the npm script. This command starts a LiveView server for testing. ```bash npm run e2e:test ``` -------------------------------- ### Install npm dependencies and Playwright browsers Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/test/e2e/README.md Before running tests, install necessary npm packages and Playwright's browser binaries. ```bash npm ci npx playwright install ``` -------------------------------- ### LiveComponent Handle Event Start Metadata Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/telemetry.md Metadata for the [:phoenix, :live_component, :handle_event, :start] telemetry event. Includes event details and parameters. ```elixir %{ socket: Phoenix.LiveView.Socket.t, component: atom, event: String.t(), params: unsigned_params } ``` -------------------------------- ### Install Polyfills for IE11 Support Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/README.md Use this npm command to install the required polyfills for IE11 compatibility. Ensure you specify the assets directory with the --prefix flag. ```shell $ npm install --save --prefix assets mdn-polyfills url-search-params-polyfill formdata-polyfill child-replace-with-polyfill classlist-polyfill new-event-polyfill @webcomponents/template shim-keyboard-event-key core-js ``` -------------------------------- ### LiveView Mount Start Telemetry Event Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/telemetry.md Dispatched before the mount/3 callback. Includes system time for measurement and socket, params, session, and uri for metadata. ```elixir [:phoenix, :live_view, :mount, :start] ``` ```elixir %{system_time: System.monotonic_time} ``` ```elixir %{ socket: Phoenix.LiveView.Socket.t, params: unsigned_params | :not_mounted_at_router, session: map, uri: String.t() | nil } ``` -------------------------------- ### Create a New Phoenix LiveView App Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/README.md Use the `mix phx.new` command to generate a new Phoenix application with LiveView pre-installed. Ensure you have the `phx_new` archive installed first. ```bash $ mix archive.install hex phx_new $ mix phx.new demo ``` -------------------------------- ### LiveComponent Update Start Metadata Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/telemetry.md Metadata for the [:phoenix, :live_component, :update, :start] telemetry event. Contains socket and component assignment details. ```elixir %{ socket: Phoenix.LiveView.Socket.t, component: atom, assigns_sockets: [{map(), Phoenix.LiveView.Socket.t}] } ``` -------------------------------- ### HTML Button with Click and Keydown Events Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/syncing-changes.md Example of HTML elements with `phx-click` and `phx-window-keydown` attributes. LiveView will add `-loading` classes to these elements when events are pushed to the server. ```heex ``` -------------------------------- ### Server-Pushed Event Example Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/js-interop.md Server pushes a 'highlight' event with an item ID. This is useful for drawing user attention to specific elements. ```heex
item.id} class="item"> {item.title}
``` ```elixir def handle_info({:item_updated, item}, socket) do {:noreply, push_event(socket, "highlight", %{id: "item-" <> item.id})} end ``` ```javascript let liveSocket = new LiveSocket(...) window.addEventListener("phx:highlight", (e) => { let el = document.getElementById(e.detail.id) if(el) { // logic for highlighting } }) ``` -------------------------------- ### LiveView Handle Params Start Telemetry Event Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/telemetry.md Dispatched before the handle_params/3 callback. Measures the system time and includes metadata for the socket, params, and uri. ```elixir [:phoenix, :live_view, :handle_params, :start] ``` ```elixir %{system_time: System.monotonic_time} ``` ```elixir %{ socket: Phoenix.LiveView.Socket.t, params: unsigned_params, uri: String.t() } ``` -------------------------------- ### LiveView Mount Callback for Authorization Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/security-model.md Implement authorization logic within the `mount/3` callback to ensure users are authenticated and confirmed before proceeding. This example redirects unconfirmed users to the login page. ```elixir def mount(_params, %{"user_id" => user_id} = _session, socket) do socket = assign(socket, current_user: Accounts.get_user!(user_id)) socket = if socket.assigns.current_user.confirmed_at do socket else redirect(socket, to: "/login") end {:ok, socket} end ``` -------------------------------- ### S3 CORS Configuration Example Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/external-uploads.md An example of CORS configuration for an S3 bucket to allow client-side uploads. Ensure 'AllowedOrigins' includes your application's domain. ```json [ { "AllowedHeaders": [ "*" ], "AllowedMethods": [ "PUT", "POST" ], "AllowedOrigins": [ "https://web.myapp.com", // Add any other domains desired, or * for wildcard. ], "ExposeHeaders": [] } ] ``` -------------------------------- ### Run JavaScript End-to-End Tests Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/README.md Execute JavaScript end-to-end tests. Ensure all dependencies are installed before running. ```bash $ mix deps.get $ npm ci $ npm run e2e:test ``` -------------------------------- ### LiveView Render Start Telemetry Event Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/telemetry.md Dispatched immediately before a render starts, which may involve Phoenix.LiveView.render/1 or Phoenix.LiveComponent.render/1 callbacks. Measures system time and includes socket, force?, and changed? metadata. ```elixir [:phoenix, :live_view, :render, :start] ``` ```elixir %{system_time: System.monotonic_time} ``` ```elixir %{ socket: Phoenix.LiveView.Socket.t, force?: boolean, changed?: boolean } ``` ```elixir %{ component: module, id: term, cid: integer } ``` -------------------------------- ### LiveView Handle Event Start Telemetry Event Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/telemetry.md Dispatched before the handle_event/3 callback. Measures the system time and includes metadata for the socket, event name, and params. ```elixir [:phoenix, :live_view, :handle_event, :start] ``` ```elixir %{system_time: System.monotonic_time} ``` ```elixir %{ socket: Phoenix.LiveView.Socket.t, event: String.t(), params: unsigned_params } ``` -------------------------------- ### Run All JavaScript Tests Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/README.md Execute all JavaScript tests. This involves fetching Elixir dependencies, installing Node.js dependencies, and running the npm test script. ```bash $ mix deps.get $ npm ci $ npm test ``` -------------------------------- ### Load LiveSocket for JS Interop Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/js-interop.md To enable JS Hooks and JS commands on regular pages, the page must load and connect `LiveSocket`. This setup is similar to a standard LiveView page. ```javascript import {LiveSocket} from "phoenix_live_view" const liveSocket = new LiveSocket("/live", Socket, {hooks: Hooks}) liveSocket.connect() ``` -------------------------------- ### Including Custom Metadata in Client Events Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/bindings.md Configure `LiveSocket` to send custom metadata with client events. This example sends click coordinates and `altKey` status for all clicks. ```javascript let liveSocket = new LiveSocket("/live", Socket, { params: {_csrf_token: csrfToken}, metadata: { click: (e, el) => { return { altKey: e.altKey, clientX: e.clientX, clientY: e.clientY } } } }) ``` -------------------------------- ### Animate Element on Mount with phx-mounted Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/bindings.md Use the `phx-mounted` binding to trigger a JavaScript transition when an element is added to the DOM. This example uses `JS.transition` for a 'ping' animation. ```heex
``` -------------------------------- ### Handling Click Events with phx-value- Attributes on Server Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/bindings.md Example of a server-side `handle_event` function that receives parameters from `phx-value-` attributes. The parameters are available as a map. ```elixir def handle_event("inc", %{"myvar1" => "val1", "myvar2" => "val2"}, socket) do end ``` -------------------------------- ### Throttling Button Clicks Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/bindings.md Use `phx-throttle` to limit the rate of events like clicks. This example ensures the 'volume_up' event is sent at most once per second. ```heex ``` -------------------------------- ### Import Polyfills in JavaScript Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/README.md Import the necessary polyfills into your application's JavaScript file to ensure compatibility with older browsers. This example shows the imports for Phoenix LiveView's app.js. ```javascript // assets/js/app.js import "mdn-polyfills/Object.assign" import "mdn-polyfills/CustomEvent" import "mdn-polyfills/String.prototype.startsWith" import "mdn-polyfills/Array.from" import "mdn-polyfills/Array.prototype.find" import "mdn-polyfills/Array.prototype.some" import "mdn-polyfills/NodeList.prototype.forEach" import "mdn-polyfills/Element.prototype.closest" import "mdn-polyfills/Element.prototype.matches" import "mdn-polyfills/Node.prototype.remove" import "child-replace-with-polyfill" import "url-search-params-polyfill" import "formdata-polyfill" import "classlist-polyfill" import "new-event-polyfill" import "@webcomponents/template" import "shim-keyboard-event-key" import "event-submitter-polyfill" import "core-js/features/set" import "core-js/features/url" import {Socket} from "phoenix" import {LiveSocket} from "phoenix_live_view" ... ``` -------------------------------- ### Button with Tailwind Loading Variant Class Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/syncing-changes.md Example of a button using a Tailwind CSS variant (`phx-click-loading:opacity-50`) to apply styling when the element is in a loading state. This leverages the Tailwind integration for dynamic styling. ```heex ``` -------------------------------- ### Initialize Uploads in LiveView Mount Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/uploads.md Use `allow_upload/3` in the `mount` function to configure upload specifications like accepted file types and maximum entries. This sets up the upload handling for a specific upload reference. ```elixir iex> @impl Phoenix.LiveView def mount(_params, _session, socket) do {:ok, socket |> assign(:uploaded_files, []) |> allow_upload(:avatar, accept: ~w(.jpg .jpeg), max_entries: 2)} end ``` -------------------------------- ### Live sorting with handle_params Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/live-navigation.md Implement live sorting by using `patch` links and handling URL parameters in the `handle_params/3` callback. This allows updating the LiveView state based on URL changes without remounting. ```heex <.link patch={~p"/users?sort_by=name"}>Sort by name ``` -------------------------------- ### Mount and Paginate Posts Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/bindings.md Initializes the LiveView by assigning pagination state and fetching the first page of posts. This function is responsible for fetching data and updating the stream. ```elixir def mount(_, _, socket) do {:ok, socket |> assign(page: 1, per_page: 20) |> paginate_posts(1)} end defp paginate_posts(socket, new_page) when new_page >= 1 do %{per_page: per_page, page: cur_page} = socket.assigns posts = Blog.list_posts(offset: (new_page - 1) * per_page, limit: per_page) {posts, at, limit} = if new_page >= cur_page do {posts, -1, per_page * 3 * -1} else {Enum.reverse(posts), 0, per_page * 3} end case posts do [] -> assign(socket, end_of_timeline?: at == -1) [_ | _] = posts -> socket |> assign(end_of_timeline?: false) |> assign(:page, new_page) |> stream(:posts, posts, at: at, limit: limit) end end ``` -------------------------------- ### Customize JS Push Event with Options Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/bindings.md Shows how to customize a `JS.push` command with options like `target` and `loading` to control server interaction and client-side feedback. ```heex ``` -------------------------------- ### Run Elixir Tests Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/README.md Execute Elixir tests by first fetching dependencies and then running the test suite. ```bash $ mix deps.get $ mix test ``` -------------------------------- ### Router Configuration with `on_mount` Hook Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/security-model.md Configure the `on_mount` hook in the router's `live_session` to apply authentication logic to all LiveViews within that session. ```elixir live_session :default, on_mount: MyAppWeb.UserLiveAuth do # Your routes end ``` -------------------------------- ### LiveView Mount and Presign Upload Function Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/external-uploads.md Implements the LiveView mount function to allow external uploads and defines the presign_upload function to generate pre-signed S3 URLs. Ensure the SimpleS3Upload module is available. ```elixir def mount(_params, _session, socket) do {:ok, socket |> assign(:uploaded_files, []) |> allow_upload(:avatar, accept: :any, max_entries: 3, external: &presign_upload/2)} end defp presign_upload(entry, socket) do uploads = socket.assigns.uploads bucket = "phx-upload-example" key = "public/#{entry.client_name}" config = %{ region: "us-east-1", access_key_id: System.fetch_env!("AWS_ACCESS_KEY_ID"), secret_access_key: System.fetch_env!("AWS_SECRET_ACCESS_KEY") } {:ok, fields} = SimpleS3Upload.sign_form_upload(config, bucket, key: key, content_type: entry.client_type, max_file_size: uploads[entry.upload_config].max_file_size, expires_in: :timer.hours(1) ) meta = %{uploader: "S3", key: key, url: "http://#{bucket}.s3-#{config.region}.amazonaws.com", fields: fields} {:ok, meta, socket} end ``` -------------------------------- ### Integrating Colocated Hooks in app.js Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/js-interop.md Import colocated hooks from the `phoenix-colocated` package into your `app.js` to make them available to LiveView. This example shows the import and hook merging. ```diff ... import {Socket} from "phoenix" import {LiveSocket} from "phoenix_live_view" import topbar from "../vendor/topbar" + import {hooks as colocatedHooks} from "phoenix-colocated/my_app" let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content") let liveSocket = new LiveSocket("/live", Socket, { longPollFallbackMs: 2500, params: {_csrf_token: csrfToken}, + hooks: {...colocatedHooks} }) ``` -------------------------------- ### Show Modal with Fade-in Transition Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/bindings.md Demonstrates how to show a modal element with a fade-in transition using `JS.show`. ```heex ``` -------------------------------- ### Mount LiveView with Upload Component Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/uploads.md Initializes the LiveView socket with upload capabilities for a specific input. Configure accepted file types and maximum entries. ```elixir defmodule MyAppWeb.UploadLive do use MyAppWeb, :live_view @impl Phoenix.LiveView def mount(_params, _session, socket) do {:ok, socket |> assign(:uploaded_files, []) |> allow_upload(:avatar, accept: ~w(.jpg .jpeg), max_entries: 2)} end @impl Phoenix.LiveView def handle_event("validate", _params, socket) do {:noreply, socket} end @impl Phoenix.LiveView def handle_event("cancel-upload", %{"ref" => ref}, socket) do {:noreply, cancel_upload(socket, :avatar, ref)} end @impl Phoenix.LiveView def handle_event("save", _params, socket) do uploaded_files = consume_uploaded_entries(socket, :avatar, fn %{path: path}, _entry -> dest = Path.join([:code.priv_dir(:my_app), "static", "uploads", Path.basename(path)]) # You will need to create `priv/static/uploads` for `File.cp!/2` to work. File.cp!(path, dest) {:ok, ~p"/uploads/#{Path.basename(dest)}"} end) {:noreply, update(socket, :uploaded_files, &(&1 ++ uploaded_files))} end defp error_to_string(:too_large), do: "Too large" defp error_to_string(:too_many_files), do: "You have selected too many files" defp error_to_string(:not_accepted), do: "You have selected an unacceptable file type" end ``` ``` -------------------------------- ### Default `live_view` Configuration with `on_mount` Hook Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/security-model.md Apply an `on_mount` hook to all LiveViews by default by defining it within the `MyAppWeb.live_view` function. ```elixir def live_view do quote do use Phoenix.LiveView on_mount MyAppWeb.UserLiveAuth unquote(html_helpers()) end end ``` -------------------------------- ### Colocated Hook in HEEx Component Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/js-interop.md Define JavaScript logic directly within HEEx components using `Phoenix.LiveView.ColocatedHook`. This example shows an input hook that formats phone numbers. ```elixir def phone_number_input(assigns) do ~H""" """ end ``` -------------------------------- ### Live Session with Router-Level on_mount Hook Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/security-model.md Configure `live_session` with an `on_mount` option to enforce authentication hooks at the router level for all LiveViews within that session. This avoids repeating the hook on every LiveView. ```elixir scope "/" do pipe_through [:authenticate_user] live_session :default, on_mount: MyAppWeb.UserLiveAuth do live ... end end scope "/admin" do pipe_through [:authenticate_admin] live_session :admin, on_mount: MyAppWeb.AdminLiveAuth do live ... end end ``` -------------------------------- ### Render File Input with LiveFileComponent Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/uploads.md Use the `live_file_input/1` component to render a file input element. Attributes like `id`, `accept`, and `multiple` are automatically set based on the `allow_upload/3` specification. ```heex <%!-- lib/my_app_web/live/upload_live.html.heex --%>
<.live_file_input upload={@uploads.avatar} />
``` -------------------------------- ### Format Files Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/README.md Format both Elixir and JavaScript files according to project standards. ```bash $ mix format $ npm run js:format ``` -------------------------------- ### Thermostat LiveView Module Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/introduction/welcome.md Defines a basic LiveView with render, mount, and handle_event callbacks to manage and display a temperature. Uses HEEx for templating. ```elixir defmodule MyAppWeb.ThermostatLive do use MyAppWeb, :live_view def render(assigns) do ~H""" Current temperature: {@temperature}°F """ end def mount(_params, _session, socket) do temperature = 70 # Let's assume a fixed temperature for now {:ok, assign(socket, :temperature, temperature)} end def handle_event("inc_temperature", _params, socket) do {:noreply, update(socket, :temperature, &(&1 + 1))} end end ``` -------------------------------- ### Use Live Title Component Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/live-layouts.md Utilize the `live_title` component for automatic prefixing and suffixing of the page title, supporting dynamic updates. ```heex {assigns[:page_title]} ``` -------------------------------- ### LiveView Module Configuration with `on_mount` Hook Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/security-model.md Specify an `on_mount` hook directly within a specific LiveView module to apply authentication logic only to that LiveView. ```elixir defmodule MyAppWeb.PageLive do use MyAppWeb, :live_view on_mount MyAppWeb.UserLiveAuth ... end ``` -------------------------------- ### LiveView `on_mount` Hook for Authentication Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/security-model.md Encapsulate authentication and authorization logic in an `on_mount` hook for reusable execution on every LiveView mount. This hook fetches the user by session token and halts if the user is not confirmed. ```elixir defmodule MyAppWeb.UserLiveAuth do import Phoenix.Component import Phoenix.LiveView alias MyAppWeb.Accounts # from `mix phx.gen.auth` def on_mount(:default, _params, %{"user_token" => user_token} = _session, socket) do socket = assign_new(socket, :current_user, fn -> Accounts.get_user_by_session_token(user_token) end) if socket.assigns.current_user.confirmed_at do {:cont, socket} else {:halt, redirect(socket, to: "/login")} end end end ``` -------------------------------- ### Read Both Parameters and Session in Mount Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/introduction/welcome.md Combines reading both 'house' from parameters and 'current_user_id' from the session to fetch specific thermostat data. This is a common pattern for authenticated, context-aware data retrieval. ```elixir def mount(%{"house" => house}, %{"current_user_id" => user_id}, socket) do temperature = Thermostat.get_house_reading(user_id, house) {:ok, assign(socket, :temperature, temperature)} end ``` -------------------------------- ### Display Page Loading Status with Topbar Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/syncing-changes.md Listen for 'phx:page-loading-start' and 'phx:page-loading-stop' events on the window to show and hide a loading indicator like topbar. This is useful for providing visual feedback during navigation. ```javascript import topbar from "topbar" window.addEventListener("phx:page-loading-start", info => topbar.show(500)) window.addEventListener("phx:page-loading-stop", info => topbar.hide()) ``` -------------------------------- ### Client State During Submit and Server Processing Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/syncing-changes.md Shows the client's UI state after the user finishes typing and presses submit, while a server debounce event is still being processed. ```plain_text [ hello@example.com ] ------------ SUBMITTING ------------ ``` -------------------------------- ### Show Modal by Adding Class Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/bindings.md Shows a modal by adding a 'show' class to the element with a fade-in transition using `JS.add_class`. ```heex ``` -------------------------------- ### Target Param for Input Change Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/form-bindings.md Shows how the _target param is structured in the server's handle_event/3 when an input triggers a change event. The keyspace of the input name is included. ```heex ``` ```Elixir %{"_target" => ["user", "username"], "user" => %{"username" => "Name"}} ``` -------------------------------- ### Testing Viewport Events with render_hook Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/bindings.md Demonstrates how to test viewport events in a LiveView using `Phoenix.LiveViewTest.render_hook/3`. ```elixir view |> element("#posts") |> render_hook("next-page") ``` -------------------------------- ### Configure Uploads in LiveView Mount Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/external-uploads.md Configure the LiveView mount function to allow external uploads, specifying an external function for generating signed URLs. ```elixir def mount(_params, _session, socket) do {:ok, socket |> assign(:uploaded_files, []) |> allow_upload(:avatar, accept: :any, max_entries: 3, external: &presign_upload/2)} end ``` -------------------------------- ### Button Binding for Client-Server Interaction Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/introduction/welcome.md Renders a button with a 'phx-click' binding that triggers the 'inc_temperature' event on the server when clicked. ```html ``` -------------------------------- ### Client State Before Server Response Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/syncing-changes.md Illustrates the client's UI state when an email input is partially typed and a debounce event is in flight. ```plain_text [ hello@example. ] ------------ SUBMIT ------------ ``` -------------------------------- ### Client-side navigation with link component Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/live-navigation.md Use `patch` or `navigate` attributes in the `Phoenix.Component.link/1` component to trigger live navigation from the client. `patch` updates the current LiveView, while `navigate` mounts a new one. ```heex <.link patch={~p"/pages/#{@page + 1}"}>Next ``` -------------------------------- ### HEEx Comprehension with `:key` for Optimized Tracking Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/assigns-eex.md When using comprehensions, specify a `:key` attribute (e.g., `post.id`) to help LiveView track changes more efficiently within the collection, especially for insertions or deletions. ```heex

{expand_title(post.title)}

``` -------------------------------- ### LiveView Server Callbacks for Form Recovery Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/form-bindings.md Implement `handle_event` callbacks on the server to handle form validation and custom recovery logic. The `validate_wizard_step` handles current step validations, while `recover_wizard` rebuilds state based on client input. ```elixir def handle_event("validate_wizard_step", params, socket) do # regular validations for current step {:noreply, socket} end def handle_event("recover_wizard", params, socket) do # rebuild state based on client input data up to the current step {:noreply, socket} end ``` -------------------------------- ### Handle Form Reset Event Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/form-bindings.md Demonstrates how to handle a form reset event on the server. A phx-change event is emitted with a _target param indicating the reset name. ```heex
...
``` ```Elixir def handle_event("changed", %{"_target" => ["reset"]} = params, socket) do # handle form reset end def handle_event("changed", params, socket) do # handle regular form change end ``` -------------------------------- ### Handle Next and Previous Page Events Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/bindings.md Handles 'next-page' and 'prev-page' events to update pagination and fetch new posts. It includes logic to reset to the first page if the viewport is overrun. ```elixir def handle_event("next-page", _, socket) do {:noreply, paginate_posts(socket, socket.assigns.page + 1)} end def handle_event("prev-page", %{"_overran" => true}, socket) do {:noreply, paginate_posts(socket, 1)} end def handle_event("prev-page", _, socket) do if socket.assigns.page > 1 do {:noreply, paginate_posts(socket, socket.assigns.page - 1)} else {:noreply, socket} end end ``` -------------------------------- ### Basic Form with Change and Submit Bindings Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/form-bindings.md Use `phx-change` and `phx-submit` on a form component to handle input changes and form submissions. The form is rendered using the `.form` function component. ```heex <.form for={@form} id="my-form" phx-change="validate" phx-submit="save"> <.input type="text" field={@form[:username]} /> <.input type="email" field={@form[:email]} /> ``` -------------------------------- ### Run JavaScript Unit Tests Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/README.md Execute JavaScript unit tests. Includes an option to automatically run tests for changed files. ```bash $ mix deps.get $ npm ci $ npm run js:test # to automatically run tests for files that have been changed $ npm run js:test.watch ``` -------------------------------- ### Pushing Events to LiveView with Reply Callback Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/js-interop.md Use `pushEvent` within a hook to send data to the LiveView and handle a reply using a callback function. The server must respond with `{:reply, map, socket}`. ```heex
Click me for a message!
``` ```javascript Hooks.ClickMeHook = { mounted() { this.el.addEventListener("click", () => { // Push event to LiveView with callback for reply this.pushEvent("get_message", {}, (reply) => { console.debug(reply.message); }); }); } } ``` ```elixir def handle_event("get_message", _params, socket) do # Use :reply to respond to the pushEvent {:reply, %{message: "Hello from LiveView!"}, socket} end ``` -------------------------------- ### Simulate Network Latency in LiveView Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/js-interop.md Use the enableLatencySim function on the LiveSocket instance to simulate network latency for testing UX. The function accepts an integer in milliseconds for the one-way latency. Debug state persists for the browser session. ```javascript // app.js let liveSocket = new LiveSocket(...) liveSocket.connect() window.liveSocket = liveSocket // in the browser's web console >> liveSocket.enableLatencySim(1000) [Log] latency simulator enabled for the duration of this browser session. Call disableLatencySim() to disable ``` -------------------------------- ### HEEx Comprehension with `for` Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/assigns-eex.md Use `for` within HEEx templates to iterate over lists and collections. LiveView optimizes static parts and tracks changes within the collection. ```heex <%= for post <- @posts do %>

{expand_title(post.title)}

<% end %> ``` -------------------------------- ### Server-side navigation with push_patch Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/live-navigation.md Trigger live navigation from the server using `Phoenix.LiveView.push_patch/2`. This is useful for updating the current LiveView's URL and parameters without a full page reload. ```elixir {:noreply, push_patch(socket, to: ~p"/pages/#{@page + 1}")} ``` -------------------------------- ### Defining Live Sessions with Different Authentication Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/security-model.md Use `live_session` to group LiveViews and specify different authentication pipelines for distinct user scopes. This ensures that navigation events within the same session skip HTTP requests. ```elixir scope "/" do pipe_through [:authenticate_user] get ... live_session :default do live ... end end scope "/admin" do pipe_through [:http_auth_admin] get ... live_session :admin do live ... end end ``` -------------------------------- ### Run specific test in headed mode Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/test/e2e/README.md Execute a particular test file and line number in headed mode, targeting a specific browser project. ```bash npm run e2e:test -- tests/streams.spec.js:9 --project chromium --headed ``` -------------------------------- ### Apply Loading State to Specific Element Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/syncing-changes.md Use `JS.push` with a `loading` option to apply a loading state to a specific element identified by a selector, rather than just the clicked element. ```heex ``` -------------------------------- ### LiveSocket Configuration with Uploaders Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/external-uploads.md Configures the LiveSocket in app.js to include the custom uploaders. This step connects the server-side metadata uploader name ('S3') with the client-side JavaScript implementation. ```javascript // for uploading to S3 import Uploaders from "./uploaders" let liveSocket = new LiveSocket("/live", Socket, { params: {_csrf_token: csrfToken}, uploaders: Uploaders } ) ``` -------------------------------- ### Render a LiveComponent Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/introduction/welcome.md LiveComponents encapsulate state, markup, and events. They are rendered using the `live_component/1` function and have their own callbacks. ```heex <.live_component module={UserComponent} id={user.id} user={user} /> ``` -------------------------------- ### Display Upload Entries and Progress Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/uploads.md Iterate over upload entries using `entry <- @uploads.avatar.entries` to display file information, progress bars, and handle cancellation. Use `upload_errors/2` and `upload_errors/1` to show specific entry or general upload errors. ```heex <%!-- lib/my_app_web/live/upload_live.html.heex --%> <%!-- use phx-drop-target with the upload ref to enable file drag and drop --%>
<%!-- render each avatar entry --%>
<.live_img_preview entry={entry} />
{entry.client_name}
<%!-- entry.progress will update automatically for in-flight entries --%> {entry.progress}% <%!-- a regular click event whose handler will invoke Phoenix.LiveView.cancel_upload/3 --%> <%!-- Phoenix.Component.upload_errors/2 returns a list of error atoms --%>

{error_to_string(err)}

<%!-- Phoenix.Component.upload_errors/1 returns a list of error atoms --%>

{error_to_string(err)}

``` -------------------------------- ### Toggle Modal with Transitions Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/bindings.md Demonstrates how to toggle the visibility of a modal element with specified in and out transitions using `JS.toggle`. ```heex ``` -------------------------------- ### Authorize User Actions in handle_event Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/security-model.md This snippet shows how to authorize a user within a `handle_event` callback before performing a sensitive action like deleting a project. It ensures that even if a user bypasses UI restrictions, the server-side permission check prevents unauthorized operations. ```elixir on_mount MyAppWeb.UserLiveAuth def mount(_params, _session, socket) do {:ok, load_projects(socket)} end def handle_event("delete_project", %{"project_id" => project_id}, socket) do Project.delete!(socket.assigns.current_scope, project_id) {:noreply, update(socket, :projects, &Enum.reject(&1, fn p -> p.id == project_id end))} end defp load_projects(socket) do projects = Project.all_projects(socket.assigns.current_scope) assign(socket, projects: projects) end ``` -------------------------------- ### Enable Debug Logging for LiveView Client Events Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/js-interop.md Expose the LiveSocket instance on the window object to enable debug logging in the browser's web console. This helps in troubleshooting by showing LiveView lifecycle and payload events. ```javascript // app.js let liveSocket = new LiveSocket(...) liveSocket.connect() window.liveSocket = liveSocket // in the browser's web console >> liveSocket.enableDebug() ``` -------------------------------- ### Check Test Coverage Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/README.md Generate and report on test coverage for JavaScript code. ```bash $ npm run cover $ npm run cover:report ``` -------------------------------- ### Set Root Layout in Router Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/live-layouts.md Configure the root layout for your LiveView application within the router configuration. ```elixir plug :put_root_layout, html: {MyAppWeb.Layouts, :root} ``` -------------------------------- ### LiveView Event Handling for Form Events Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/form-bindings.md Implement `handle_event` callbacks in your LiveView to process 'validate' and 'save' events triggered by the form. This includes updating the changeset, creating a user, and handling errors. ```elixir def mount(_params, _session, socket) do {:ok, assign(socket, form: to_form(Accounts.change_user(%User{})))} end def handle_event("validate", %{"user" => params}, socket) do form = %User{} |> Accounts.change_user(params) |> to_form(action: :validate) {:noreply, assign(socket, form: form)} end def handle_event("save", %{"user" => user_params}, socket) do case Accounts.create_user(user_params) do {:ok, user} -> {:noreply, socket |> put_flash(:info, "user created") |> redirect(to: ~p"/users/#{user}")} {:error, %Ecto.Changeset{} = changeset} -> {:noreply, assign(socket, form: to_form(changeset))} end end ``` -------------------------------- ### Generate Presigned Upload URL Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/external-uploads.md Implement the external upload function to generate a presigned URL for direct uploads to cloud storage. ```elixir defp presign_upload(entry, socket) do {:ok, %{"Location" => link}} = SomeTube.start_session(%{ "uploadType" => "resumable", "x-upload-content-length" => entry.client_size }) {:ok, %{uploader: "UpChunk", entrypoint: link}, socket} end ``` -------------------------------- ### Sending Values with phx-value- Attributes Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/bindings.md Utilize `phx-value-` prefixed attributes to send multiple key-value pairs with a click event. The server receives these as a map. ```heex
``` -------------------------------- ### Configuring Keydown Metadata for LiveSocket Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/bindings.md Customize the metadata sent to the server for keydown events by providing a metadata function to the LiveSocket constructor. This allows capturing specific keyboard event properties. ```javascript let liveSocket = new LiveSocket("/live", Socket, { params: {_csrf_token: csrfToken}, metadata: { keydown: (e, el) => { return { key: e.key, metaKey: e.metaKey, repeat: e.repeat } } } }) ``` -------------------------------- ### Assign Data in LiveView Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/assigns-eex.md Load data in your LiveView and assign it using `assign/2` before rendering the template. This ensures LiveView can track changes to the data. ```elixir assign(socket, :users, Repo.all(User)) ``` -------------------------------- ### Implement Minimal Validation Callback Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/uploads.md A minimal `handle_event/3` callback is required to trigger upload validation when using `phx-change` on a form. This function must be implemented to perform entry validation. ```elixir @impl Phoenix.LiveView def handle_event("validate", _params, socket) do {:noreply, socket} end ``` -------------------------------- ### Retrieve and Set Gettext Locale from Database in LiveView Mount Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/gettext.md Retrieves the user's locale from the database based on user_id from the session and sets it for Gettext. This is suitable for applications where user locale preferences are stored persistently. ```elixir def mount(_params, %{"user_id" => user_id}, socket) do user = Users.get_user!(user_id) Gettext.put_locale(MyApp.Gettext, user.locale) {:ok, socket} end ``` -------------------------------- ### Generate LiveView CRUD Interface Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/introduction/welcome.md Generates a full CRUD interface for a LiveView resource, including database schema, migrations, and LiveView modules. Use this to quickly scaffold new LiveView applications. ```shell mix phx.gen.live Blog Post posts title:string body:text ``` -------------------------------- ### Use Function Components in LiveView Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/assigns-eex.md Render reusable UI components using function components. LiveView tracks changes to the attributes passed to these components. ```heex <.show_name name={@user.name} /> ``` -------------------------------- ### LiveView Render Exception Metadata Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/telemetry.md Metadata for the [:phoenix, :live_view, :render, :exception] telemetry event. Includes socket information, reason for exception, and optional rendering details. ```elixir %{ socket: Phoenix.LiveView.Socket.t, kind: atom, reason: term, force?: boolean, changed?: boolean } ``` -------------------------------- ### Apply CSS Transition to Element Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/syncing-changes.md Employ `JS.transition` to apply CSS transitions like 'shake' to a specified element, adding visual flair to user interactions. ```heex
My Item
``` -------------------------------- ### Compute and Assign Values in LiveView Render Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/server/assigns-eex.md Instead of defining local variables for computed values in the `render` function, use `assign/2` to store them. This allows LiveView to track changes to these computed values. ```elixir def render(assigns) do sum = assigns.x + assigns.y title = assigns.title ~H"""

{title}

{sum} """ end ``` -------------------------------- ### Reactive File Input with Drag and Drop Source: https://github.com/phoenixframework/phoenix_live_view/blob/main/guides/client/form-bindings.md LiveView forms support reactive file inputs, including drag and drop via the `phx-drop-target` attribute. Use `live_file_input` for uploads. ```heex
... <.live_file_input upload={@uploads.avatar} />
```