Correctly rendering part of component in elixir conditionally

Hi, I’m having trouble rendering a component correctly in Elixir.

So this is the component, which takes in a @truck_load:

        <CardHeader
          :if={{ not is_nil(@truck_load.sand_type) }}
          background_color={{ @truck_load.sand_type_background_color }}
          text_color={{ @truck_load.sand_type_text_color }}
          title={{ @truck_load.sand_type }}
          info={{ @truck_load.measured_weight }}
        />

The info part is currently set to truck_load.measured_weight, but I need it to be truck_load.weight if the truck_load’s current_column is “dispatched”.

I know this sounds very simple, but I’ve been struggling to get it to render correctly.

Right now, I’ve set info to be this in the CardHeader component:
info={{ render_weight(@truck_load) }}

and I’ve created these helpers, which should render either the truck_load.measured_weight or truck_load.target_weight, and format them the way I want:

  defp render_weight(truck_load) do
    if truck_load.current_column == "dispatched" do
      format_measured_weight(truck_load.measured_weight)
    else
      format_measured_weight(truck_load.target_weight)
    end
  end

  defp format_measured_weight(truck_load) do
    "#{@truck_load.measured_weight} lb (#{
      Weight.convert_pounds_to_tons_and_round(@truck_load.measured_weight)
    } tons)"
  end

  defp format_target_weight(truck_load) do
    "#{@truck_load.target_weight} lb (#{
      Weight.convert_pounds_to_tons_and_round(@truck_load.target_weight)
    } tons)"
  end

But, nothing is showing up. How can I fix this?

Your private helper functions expect the entire struct (truck_load), yet in render_weight you are passing a struct’s field (truck_load.measured_weight & truck_load.target_weight). Also, inside their bodies you are using a module attribute @truck_load. These are the inconsistencies I’ve observed.

2 Likes

Thanks so much!! This was super helpful. I fixed those inconsistencies:

  defp render_weight(truck_load) do
    if truck_load.current_column == "dispatched" do
      format_target_weight(truck_load.target_weight)
    else
      format_measured_weight(truck_load.measured_weight)
    end
  end

  defp format_target_weight(weight) do
    "#{weight} testing to see if works (#{
      Weight.convert_pounds_to_tons_and_round(weight)
    } tons)"
  end

  defp format_measured_weight(weight) do
    "#{weight} lb (#{
      Weight.convert_pounds_to_tons_and_round(weight)
    } tons)"
  end

Now the format_measured_weight helper is working and rendering the weight correctly, but the format_target_weight is not. I don’t see the “testing to see if works” text I added to the format_target_weight helper, so I know that helper isn’t being hit and there must be an issue with the conditional part of my render_weight function. Is my syntax and everything correct?

Syntax-wise, everything looks alright to my eye. Is truck_load.current_column actually dispatched for what you are testing?

1 Like

ah so it turns out dispatched is an atom and not a string, so I just had to change my function to this:

  defp render_weight(truck_load) do
    if truck_load.current_column == :dispatched do
      format_target_weight(truck_load.weight)
    else
      format_measured_weight(truck_load.measured_weight)
    end
  end

Thank you so much!! You saved my day haha

Also, quick question: I’m doing an elixir course that said it’s best to avoid using if/else statements when possible. Is this true? Is my current code written in an overly verbose or naive way?

It’s a matter of personal preference. If you prefer this way, then by all means, keep it like this (you’ll be the one reading the code in the future, anyway, thus keep it the way you like it most).

The above could be written like this:

  defp render_weight(%{current_column: :dispatched} = truck_load),
    do: format_target_weight(truck_load.weight)

  defp render_weight(truck_load), do: format_measured_weight(truck_load.measured_weight)

or with a case

  defp render_weight(truck_load) do
    case truck_load.current_column do
       :dispatched -> format_target_weight(truck_load.weight)
       _ -> format_measured_weight(truck_load.measured_weight)
    end
  end

.etc

Credo is worth being mentioned in this context.

2 Likes

awesome, this really helps me understand elixir syntax better so I really appreciate it. will definitely be using credo also!