Efficiently hide/show table columns via assigns

Hi everyone, I got this very simple hide/show columns via socket assigns working but was wondering if anyone knows a better way.

I have a simple multi select (using the JS Select2 library) which allows my user to select columns to hide from a table. Selecting a column adds a character like “0” or “1” for example which is the position from left to right for the given column.

I then send an event to my live view with the selected column and add said column (“0”, “1”, “2”, etc) to a list in my assigns named hidden_columns:

In my HTML I determine which columns to show/hide based on my assigns in the following fashion, which works but just doesn’t feel like good design. Your opinion will be greatly appreciated. Can you think of a better way to show/hide columns, maybe a more efficient way?

<table class="border-collapse w-full mt-4">
  <thead>
    <tr>
      <%= if "0" not in @hidden_columns do %>
        <th class="p-1 font-bold uppercase text-sm bg-gray-200 text-gray-600 hidden lg:table-cell">Class number</th>
      <% end %>

      <%= if "1" not in @hidden_columns do %>
        <th class="p-1 font-bold uppercase text-sm bg-gray-200 text-gray-600 hidden lg:table-cell">Unit number</th>
      <% end %>

      <%= if "2" not in @hidden_columns do %>
        <th class="p-1 font-bold uppercase text-sm bg-gray-200 text-gray-600 hidden lg:table-cell">Type</th>
      <% end %>

      <%= if "3" not in @hidden_columns do %>
        <th class="p-1 font-bold uppercase text-sm bg-gray-200 text-gray-600 hidden lg:table-cell">Make</th>
      <% end %>

      <%= if "4" not in @hidden_columns do %>
        <th class="p-1 font-bold uppercase text-sm bg-gray-200 text-gray-600 hidden lg:table-cell">Model</th>
      <% end %>

      <%= if "5" not in @hidden_columns do %>
        <th class="p-1 font-bold uppercase text-sm bg-gray-200 text-gray-600 hidden lg:table-cell">Class code</th>
      <% end %>

      <%= if "6" not in @hidden_columns do %>
        <th class="p-1 font-bold uppercase text-sm bg-gray-200 text-gray-600 hidden lg:table-cell">Class</th>
      <% end %>

      <%= if "7" not in @hidden_columns do %>
        <th class="p-1 font-bold uppercase text-sm bg-gray-200 text-gray-600 hidden lg:table-cell">Description</th>
      <% end %>

      <%= if "8" not in @hidden_columns do %>
        <th class="p-1 font-bold uppercase text-sm bg-gray-200 text-gray-600 hidden lg:table-cell">License plate</th>
      <% end %>

      <%= if "9" not in @hidden_columns do %>
        <th class="p-1 font-bold uppercase text-sm bg-gray-200 text-gray-600 hidden lg:table-cell">Registration</th>
      <% end %>

      <%= if "10" not in @hidden_columns do %>
        <th class="p-1 font-bold uppercase text-sm bg-gray-200 text-gray-600 hidden lg:table-cell">Year</th>
      <% end %>

      <%= if "11" not in @hidden_columns do %>
        <th class="p-1 font-bold uppercase text-sm bg-gray-200 text-gray-600 hidden lg:table-cell">Serial number</th>
      <% end %>

      <%= if "12" not in @hidden_columns do %>
        <th class="p-1 font-bold uppercase text-sm bg-gray-200 text-gray-600 hidden lg:table-cell">Location</th>
      <% end %>

      <%= if "13" not in @hidden_columns do %>
        <th class="p-1 font-bold uppercase text-sm bg-gray-200 text-gray-600 hidden lg:table-cell">Owner</th>
      <% end %>

      <%= if "14" not in @hidden_columns do %>
        <th class="p-1 font-bold uppercase text-sm bg-gray-200 text-gray-600 hidden lg:table-cell">Leasor</th>
      <% end %>

      <%= if "15" not in @hidden_columns do %>
        <th class="p-1 font-bold uppercase text-sm bg-gray-200 text-gray-600 hidden lg:table-cell">Actions</th>
      <% end %>
    </tr>
  </thead>
...............

This is not dry… I would try to get a collection of label and index and iterate over it.

headers = ["Label1"=>"0", ...]

and then

<%= for {label, key} <- headers, key not in @hidden_columns do %>
  <th><%= label %></th>
<% end %>

Not that I like those pseudo ids… I would prefer something like visible_headers with a list of visible labels, and check if label is in.

Thanks for the suggestion. What do you mean by “this is not dry”?

dry, don’t repeat yourself…

What if You want to change th styles? You would have to edit all of them.

Oh, regarding the styles. Yes I have to start using Tailwind’s@apply.

Do you think your suggestion would improve performance? (your suggestion regarding the columns not the styles)

This code is repeated 15 times… that 's what I mean :slight_smile:

Oh I see. :grinning_face_with_smiling_eyes: I will move everything into a for loop to follow the DRY convention for sure.
But in terms of speed, do you think your suggestion will make my page load any faster or not really anything significant? thanks a lot

I don’t think it’s significant in term of speed, but for refactoring.

Got it. Much appreciated.
Not to abuse your kindness but I will take any speed improving suggestions you have as well since I am repeating the same if else blocks in my actual rows like:

 <%= if "1" not in @hidden_columns do %>
        <td>
            <%= our_equipment.unit_number %>
        </td>
 <%end %>

I don’t like the condition too…

That’s why I tried to filter first. Using a visible list of labels is also a solution that don’t need a condition at all.

True thanks

This could probably also done via the new JS commands in LiveView 0.17.
You could use JS.add_class/3 and JS.remove_class/3 to show/hide the relevant columns on the client side.
Does your server need to know which columns are hidden?

You are right, I actually replaced all my Phoenx if statements for Alpine JS ones and now my app is way faster.
I still plan on sending the list of hidden columns to my server so that the columns can remain hidden after a users edits a row on my table but that is way less data and server side logic than having to compute all if else statements on the server and then send the result to the client!

1 Like