LiveView card components with Bootstrap

This is a guest post from Sophie DeBenedetto, co-author of Programming Phoenix LiveView. You can get started with your own Elixir Phoenix application in a jiffy!

You may already be reaching for LiveView components to wrap up the behavior and markup of distinct portions of your LiveView UI.

In this post, we’re going to take a single-purpose component that displays book review data in Bootstrap-style card format, and transform it into a highly-reusable component that you can use throughout your application, using LiveView component slots.

We’ll start with a simple component that uses the default slot, then we’ll use named slots and teach our component to yield variables back up to the caller. Finally, we’ll use iteration and named slots to dynamically render nested function components.

The Goal

We want to be able to dynamically render content within the markup of a Bootstrap card. When we’re done, we’ll have a set of nested function components that iterates over a list of items, and uses named slots to render a card for each one. Our function components will be generic and reusable—they won’t have awareness of what content they’re rendering, so you’ll be able to use them again and again throughout your app to display Bootstrap cards.

The Feature: Display Book Reviews

In this post, we’ll build a Bootstrap-style card component and use it to render a set of book reviews like this:

Screenshot of a list of three book reviews, each with a star rating and review text.

We’ll use our reusable card component to render each book review’s details, including the number of stars, the email of the user who left the review, and the details of the review.

We’ll start with a simple component that iterates over the list of a book’s reviews and renders each one in a card. Let’s begin.

The Simple Card Component

First up, we’ll define a module that implements a cards/1 function component to iterate over book reviews and display each one in a Bootstrap card.

defmodule LiveLibrary.CardComponent do use Phoenix.Component def cards(assigns) do ~H””” <%= for review <- @reviews do %>

<%= for _ <- do %> <% end %>
by: <%= %>

<%= review.notes %>

<% end %> “”” end end

Our function component is simple enough—it expects the provided assigns to include a @reviews assignment. It iterates over those reviews and renders a Bootstrap card to display the details of each one. Now, we can call on our function component from another template like this:

And the browser should display the following:

Screenshot of a browser window, including the review

Our simple function component is a clean way for us to encapsulate the markup used for rendering a book review.

This may be perfect for our needs. But we can make our Bootstrap card more reusable. Right now the function component contains markup for rendering content in a card, but that content is hard-coded to display book review details. We can imagine reusing this card markup elsewhere in our app to display different types of content. Let’s refactor our component to make it a little more reusable.

Dynamic Components With the Default Slot

We’ll start by taking advantage of a component feature called “slots”. Slots allow us to provide our component with blocks of HTML to render via a simple syntax:

First, we’ll take a look at how we want to be able to call our function component, then we’ll build out that functionality with slots.

We want our card component to only be responsible for rendering card markup—it shouldn’t know anything about the content it’s rendering within that markup. In other words, it shouldn’t need awareness that the content we’re rendering describes a book review.

As an intermediate step, we’ll start with a simplified version of our function component that only renders the card header:

def cards(assigns) do ~H””” <%= for review <- @reviews do %>

<%= for _ <- do %> <% end %>

<% end %> “”” end

Now, if we check out our component in the browser, we should see this:

Just the star ratings from three reviews

Next up, we’ll make the cards/1 function component a little less smart. We’ll refactor the @reviews assignment to an @items one and we’ll use the default slot to dynamically render content into the card header:

def cards(assigns) do ~H””” <%= for item <- @items do %>

<%= render_slot(@inner_block, item)

<%% end %> “”” end

We’ll break down how this works in a bit. First, let’s take a look at how we’ll render this component:

<%= for _ <- do %> <% end %>

In between the opening and closing component tags, we’re telling the component to render a Bootstrap star icon for each of the stars in a given review. This content is made available to the component as the @inner_block assigns, and the component renders it by invoking render_slot/2 with a first argument of @inner_block. Let’s take a closer look at the second argument that we’re passing to render_slot/2 now.

We’re able to refer to the review variable in the content between our component tags because we’re telling the function component to yield a variable back up to the caller by passing a second argument to render_slot/2. So, in the function component, we’re iterating through the list of items in the @items assigns. Then, when we call render_slot/2, we pass it a second argument of an individual item. This passes the value of the item variable back up to the caller and sets it equal to a variable, review, that we specified in the let assignment of our opening component tag.

With this, we’re left with a highly dynamic function component that wraps up some card markup and leaves the awareness of the content to render in that markup entirely up to the caller.

Our usage of the default slot that can render the @inner_block assignment is a little limiting though. We can only render one segment of content as the @inner_block, and we need to inject not only card header content, but also the card title and body content. We can do exactly that with the help of named slots.

Extending the Component With Named Slots

We’ll implement a named slot for each of the sections of the card component we need to inject content into. Let’s begin once again by writing out how we want to be able to call our updated component:

<:header let={review}> <%= for _ <- do %> <% end %> <:title let={review}> by: <%= %> <:body let={review}> <%= review.notes %>

Here, we’re using an opening and closing <:header>, <:title>, and <:body> tag placing some content to render in between those tags. This content will be made available in the component as the @header, @title, and @body assignment respectively. We’ve also moved the let={review} variable assignment to each individual slot tag. Now, let’s update our component to render the header, title, and body content now.

def cards(assigns) do ~H””” <%= for item <- @items do %>

<%= render_slot(@header, item) %>
<%= render_slot(@title, item) %>

<%= render_slot(@body, item) %>

<% end %> “”” end

We use render_slot/2 to render each piece of dynamic content, and we pass the value of the item variable, which evaluates to an individual review struct, back up to the caller where it is made available as the review variable thanks to our usage of let. Now, if we go back to the browser, we’ll see all of the review details rendered in an individual card:

A single review card, showing star rating in one area and review text in the other.

With that, we’ve built a reusable cards/1 component that can render a list of cards. But what about if we only want to render a single card? We can refactor our component module to implement a new function component, card/1. Then, we’ll update the cards/1 function component to iterate over the list of items in the assigns and render a card component for each one. Let’s do it.

Iteratively Render Nested Function Components

First up, we’ll define a card/1 function component like this:

def card(assigns) do ~H”””

<%= render_slot(@header, @item) %>
<%= render_slot(@title, @item) %>

<%= render_slot(@body, @item) %>

“”” end

Our new function component is simple enough—all we did was move the markup that represents an individual card into its own component. This component also assumes that it will receive an assigns that contains a @item, @header, @title, and @body assignment. Next up, let’s refactor the cards/1 component to iteratively render a card for each item:

def cards(assigns) do ~H””” <%= for item <- @items do %> <.card header={@header} title={@title} body={@body} item={item} /> <% end %> “”” end

Here, we start our iteration in the for loop. Then, we call the card/1 function component for each item, passing through the @header, @title, and @body assignment. The manner in which we call cards/1 doesn’t change. It still looks like this:

<:header let={review}> <%= for _ <- do %> <% end %> <:title let={review}> by: <%= %> <:body let={review}> <%= review.notes %>

So, the cards/1 function uses the :header, :title, and :body named slots and its assigns contains the @header, @title, and @body assignments. Then, it simply passes those assignments through to the card/1 component, which uses render_slot/1 to render the content in the original caller’s named slots.

Putting it all together, we end up with a highly dynamic and reusable function component that can render many different types of content into a list of Bootstrap cards. The cards/1 function component wraps up all of the card markup without having any awareness of what content will be rendered into that markup. We leave it entirely up to the caller to specify what content will be rendered within the card’s header, title, and body.

Fly is an awesome place to run your Elixir apps. It’s really easy to get started. You can be running in minutes.

Deploy your Elixir app today!  →

Wrap Up

In our example, we began with a single-purpose Bootstrap card LiveView component, and converted it into a versatile function component with the help of component slots. We used more advanced techniques like named slots and yielding variables up to the function component caller to make the function component even more sophisticated and dynamic. And, we used named slots and nested function components to iteratively render a list of components. You’re ready to go out and build some reusable function components of your own.

Last updated • Mar 23, 2022 Share this post on Twitter Share this post on Hacker News Share this post on Reddit Author Sophie DeBenedettoName Sophie DeBenedetto Twitter @sm_debenedetto Previous post  ↓ Build Simple Reusable Widgets Using Slots
Joker wallet pg slot, pgslot,pg slot auto,pg slot game,pgslot download,pg slot download ios,สล็อตพีจี,พีจีสล็อต,สล็อตออนไลน์,pgslot168,slot pg,พีจีสล็อตออโต้,พีจี เว็บตรง Fullsloteiei Fullslot เราคือผู้ให้บริการสล็อตออนไลน์บนมือถืออันดับ 1 รองรับทั้งIOS และ Android ไม่ต้องดาวน์โหลดให้เปลืองเน็ต มีเกมส์ให้เลือกเล่นมากกว่า 100เกมส์เติมเงิน ถอนเงินผ่านระบบอัตโนมัติ มั่นคง ปลอดภัย บริการตลอด 24 ช.ม. สล็อต Fullslot สล็อตออนไลน์ 1 client เล่นได้ทุกค่าย ไม่ต้องสมัครหลายยูสให้ปวดหัว เล่นที่ Fullsloteiei ครบจบที่เดียวฝากถอนขั้นต่ำ 1บาท Fullslot eiei สล็อตจบครบที่เดียว ยินดีต้อนรับสู่เว็บคาสิโนออนไลน์ที่ให้บริการเกมเดิมพันแบรนด์ดังมากมายและเป็นแหล่งรวมเกมที่ใหญ่ที่สุดในประเทศใทยตอนนี้ เพื่อแก้ปัญหาความต้องการที่หลากหลายของทุกท่านบางอารมณ์ต้องการเล่นเกมสล็อตหรือบางอารมณ์ต้องการเล่นเกมอื่นๆก็สามารถเล่นได้จบครบที่เดียว มียูสเซอร์เดียวเหมือนกับว่าเป็นเจ้าของโลกคุณสามารถบ่งการได้เลยว่าต้องการจะทำอะไร เล่นอะไรมีพร้อมบริการคุณ 100 percent
Joker123 fullslot คืออะไร ใครสงสัยมีคำตอบ fullslot คือ Full ในภาษาอังกฤษ แปลว่า เต็ม ทั้งหมด สมบูรณ์ space ก็คือ เกมคาสิโนออนไลน์ที่เรารู้จักกันเป็นอย่างดีนั้นคือ เกมพนันรูปแบบโปแกรมเพราะเป็นการเล่นด้วยระบบของคอมพิวเตอร์จากในอดีตเป็นตู้เกมแมชชีนแต่ในปัจจุบันเป็นเกมสล็อตออนไลน์ที่เล่นได้อย่างสะดวกผ่านหน้าเว็บไซต์ในปัจจุบันไม่ต้องดาวน์โหลดแล้วละคะ สามารถเล่นเกมได้ที่หน้าเว็บได้เลย แล้วอะไรที่เรียกว่าเป็นเกมส์สล็อตที่มีความครบครันละ นั้นก็คือ เว็บเกมที่เปิดให้บริการคาสิโนออนไลน์แบบครบวงจรไม่ต้องไปตามหาที่ไหน มีครบจบในเว็บเดียว ไม่ว่าจะเป็น แทงบอล บาคาร่า สล็อตออนไลน์ที่กำลังเป็นที่นิยมของนักลงทุนบอกเลยว่าว่า เว็บมีทั้งสามเกมนี้ให้เล่นเว็บนั้นคือเดอะเบอสของเว็บคาสิโนออนไลน์ชั้นนำปัจจุบัน opening on the web มีให้บริการอย่างแพร่หลาย บางเว็บก็จะแยกเฉพาะให้บริการบางเว็บก็จะรวบรวมสารพัดเกมเดิมพันไว้ในเว็บเดียว
Joker123 ข้อดีของ การใช้บริการเว็บที่ให้บริการเกมคาสิโนออนไลน์ครบวงจรนั้นก็คือ ไม่ต้องมีหลายยูสเซอร์ให้งงอย่างเช่นเราต้องการเล่นเกมส์ บาคาร่า แต่เว็บนี้ไม่มีก็ต้องไปสมัครเป็นสมาชิกกับเว็บอื่นให้เสียเวลาไปอีกแล้ว อีกทั้งยังต้องเติมเงินเล่นที่อาจจะทำให้เสียเงินมากกว่าได้เงินด้วยซ้ำการที่เรามียูสเซอร์เดียวแล้วสามารถเล่นได้ทุกเกมที่ต้องการถือว่าเป็นสิ่งที่คุ้มค่ามากค่ะโดยที่เติมเงินรอบเดียวแต่หาเงินได้ถึงหลายเกมส์ ยิงปืนนัดดียวได้นกหลายตัวเลยละคะและเว็บเหล่านี้โดยส่วนมากจะเป็นเว็บที่ใหญ่ มีมาตรฐานสูง การทำงานบริการเป็นระบบ เชื่อถือได้ส่วนมากจะมีประสบการณ์ด้านการบริการเกมคาสิโนสูงมาก ความแม่นยำดีเยี่ยมทำให้การลงทุนของเรานั้นจะมีความปลอดภัยมากนั้นเองค่ะแล้วการที่จะใช้บริการเกมก็ไม่ต้องสับสนไปค่ะ จะมีการแยกหน้าเว็บเข้าใช้บริการอย่างละเอียดเช่น เข้า Ufa ,เว็บ Ufabet, บาคาร่าฟรี ,เว็บ Royal, Ufa PGSLOT

แบ่งให้ชัดเจนสามารถเข้าไปคลิ๊กเลยเล่นได้สบายเลยละคะ เป็นอย่างไรบางคะก็หวังว่าบทความนี้พอจะทำให้ทุกท่านเข้าใจความหมายของ fullslotและตัดสินใจสำหรับการลงทุนของท่านเองให้เหมาะสมกับความต้องการเพราะการที่จะมีเกมครบหรือไม่ครบของคาสิโนแต่ละเว็บนั้น ข้อดีข้อเสียก็จะขึ้นอยู่กับความต้องการของผู้ใช้บริการใครที่ต้องการเกมที่เป็นสล็อตโดยตรงก็สามารถเลือกเว็บที่มีความเชี่ยวชาญดูแลเกมสล็อตออนไลน์โดยตรง ก็ได้แต่ใครที่ต้องการทุกอย่างในหนึ่งเดียวเพื่อเพิ่มรสชาติของการลงทุนให้มีความสนุกมากยิ่งขึ้นก็เลือกเว็บที่ตอบโจทย์ตรงสไตล์ของแต่ละท่านนะคะสุดท้านนี้ก็ข้อให้การลงทุนของคุณประสบความสำเร็จค่ะ สล็อต

Leave a Comment