#development #elixir #phoenix

Phoenix LiveView is a powerful library that enables real-time interactivity in web applications, without requiring complex JavaScript frameworks. It's especially loved for its ability to keep everything dynamic and maintainable in Elixir, while still allowing fine-tuned control with JavaScript when necessary.

In some cases, you'll want to enhance the user experience by adding simple JavaScript functionalities. For example, you may want to make all links inside a specific section open in a new tab. In jQuery, this is a breeze, but you can do it equally well in vanilla JavaScript in a Phoenix LiveView app by using LiveView hooks. Let's walk through how to do this.

Step 1: The JavaScript Code

If you're familiar with jQuery, you might recognize the following snippet that opens all links inside an element with id="content" in a new tab:

1$(function(){
2  $("#content a").attr("target", "_blank");
3});

However, in a modern Phoenix LiveView app, we aim to avoid jQuery in favor of vanilla JavaScript. So, the same functionality in vanilla JavaScript looks like this:

1document.addEventListener("DOMContentLoaded", function() {
2    var links = document.querySelectorAll("#content a");
3    links.forEach(function(link) {
4        link.setAttribute("target", "_blank");
5    });
6});

This code selects all anchor (<a>) elements inside an element with the id="content" and sets their target attribute to _blank, making them open in a new tab when clicked.

However, Phoenix LiveView dynamically updates the DOM, so just adding this JavaScript on page load won't suffice because the links may be added or updated later by LiveView. To handle this dynamically, we'll use LiveView Hooks.

Step 2: Introducing Phoenix LiveView Hooks

LiveView Hooks allow you to execute JavaScript when specific LiveView components are mounted or updated. This is incredibly useful when you want to manipulate the DOM after LiveView has updated the content.

Let's create a hook that ensures all links inside the #content element will always open in a new tab, even when the content changes dynamically.

Step 3: Creating the LiveView Hook

We'll start by defining a new JavaScript hook. Create a hooks.js file (or add this to an existing file, such as app.js), and include the following code:

 1let hooks = {};
 2
 3hooks.OpenLinksInNewTab = {
 4  mounted() {
 5    this.updateLinks();
 6  },
 7  updated() {
 8    this.updateLinks();
 9  },
10  updateLinks() {
11    var links = this.el.querySelectorAll("a");
12    links.forEach(function(link) {
13      link.setAttribute("target", "_blank");
14    });
15  }
16};
17
18export default hooks;

What's Happening Here?

  • mounted(): This function runs when the element is first added to the DOM. We call updateLinks() here to ensure that when the component is initially rendered, all links inside it will open in a new tab.
  • updated(): LiveView can update components without reloading the whole page. To ensure that any newly rendered links behave the same way, we also call updateLinks() whenever the component is updated.
  • updateLinks(): This helper function selects all anchor tags within the element and sets their target attribute to _blank, making sure all links open in a new tab.

Step 4: Adding the Hook to Your LiveView App

Now, we need to attach this hook to our LiveView socket connection. In your app.js file, modify it to load your hooks and connect them to the LiveSocket.

1import { Socket } from "phoenix";
2import { LiveSocket } from "phoenix_live_view";
3import hooks from "./hooks"; // Adjust the path based on where you store hooks.js
4
5let liveSocket = new LiveSocket("/live", Socket, { hooks: ooks });
6liveSocket.connect();

This code registers the Hooks object (containing the OpenLinksInNewTab hook) with the LiveSocket connection.

Step 5: Using the Hook in Your LiveView Template

To enable this hook in your LiveView template, attach it to the DOM element where your links reside. For example, you might add it like this:

1<div id="content" phx-hook="OpenLinksInNewTab">
2  <a href="https://example.com">Example</a>
3  <!-- More links here -->
4</div>

This ensures that the OpenLinksInNewTab hook is applied to the #content element, and every time LiveView updates this section, the hook will run and update the links.

Step 6: Testing the Functionality

To see it in action:

  • Navigate to a page in your Phoenix app that uses this LiveView.
  • Inspect the links inside the #content element to ensure they now have the target="_blank" attribute.
  • Click on any link, and it should open in a new tab.

Conclusion

By leveraging Phoenix LiveView Hooks, we can easily integrate dynamic JavaScript behavior like opening links in a new tab. This approach allows you to enhance your LiveView apps without compromising on the core benefits of server-rendered interactivity.

Not only does this method keep your JavaScript minimal, but it also ensures compatibility with the LiveView lifecycle, making it the ideal way to manage dynamic content changes in a modern Phoenix application.

Whether you're working with links, form elements, or other dynamic content, LiveView hooks provide an elegant way to extend functionality while maintaining performance and simplicity.