I am using LiveView uploads for file upload and allowing multiple file uploads at once.
Beside the parameters set by allow_upload/3, I need to parse the filename of each file, break it into elements, add elements as editable input fields and validate them against the db scheme. Once the user hits a submit button, everything should be sent.
What I currently have looks something like this:
<.form let={f} for={@changeset} phx-change="validate" phx-submit="save" phx-target={@myself}>
<div class="row m-0 mb-2">
<%= live_file_input @uploads.files, class: "form-control rounded-0"%>
</div>
<div class="row m-0 mb-2">
<%= for error <- upload_errors(@uploads.files) do %>
<div class="alert alert-danger">
<%= error_to_string(error) %>
</div>
<% end %>
</div>
<div class="row m-0 mb-2">
<table class="table table-borderless table-sm">
<tr>
<th></th>
<th>Field1</th>
<th>Field2</th>
<th>Field3</th>
<th>Field4</th>
<th>Field5</th>
<th>Field6</th>
<th>Field7</th>
<th>Field8</th>
<th>Field9</th>
</tr>
<%= for entry <- @uploads.files.entries do %>
<%= list_entry(f, entry, assigns)%>
<%= list_upload_errors(f, entry, assigns)%>
<% end %>
</table>
</div>
</.form>
with helper functions being defined as
def list_entry(f, entry, assigns) do
parsed_filename = parse_filename(entry.client_name)
~H"""
<tr>
<td class="p-0" style="vertical-align: middle">
<button class="btn btn-primary p-0 d-flex justify-content-center align-items-center rounded-0" type="button" phx-target={@myself} phx-click="cancel_upload" phx-value-ref={entry.ref}>
<%= Bootstrap.Icons.x_lg(width: 20, height: 20, style: "color: white") %>
</button>
</td>
<td class="p-0 ps-1 pe-1" style="vertical-align: middle"><%= entry.client_name %></td>
<td class="p-0"><%= text_input f, :field1, value: parsed_filename.field1, style: "width: 100%;" %></td>
<td class="p-0"><%= text_input f, :field2, value: parsed_filename.field2, style: "width: 100%;" %></td>
<td class="p-0"><%= text_input f, :field3, value: parsed_filename.field3, style: "width: 100%;" %></td>
<td class="p-0"><%= text_input f, :field4, value: parsed_filename.field4, style: "width: 100%;" %></td>
<td class="p-0"><%= text_input f, :field5, value: parsed_filename.field5, style: "width: 100%;" %></td>
<td class="p-0"><%= text_input f, :field6, value: parsed_filename.field6, style: "width: 100%;" %></td>
<td class="p-0"><%= text_input f, :field7, value: parsed_filename.field7, style: "width: 100%;" %></td>
<td class="p-0"><%= text_input f, :field8, value: parsed_filename.field8, style: "width: 100%;" %></td>
</tr>
"""
end
def list_upload_errors(f, entry, assigns) do
file_errors_present = length(upload_errors(assigns.uploads.files, entry)) > 0
input_errors_present = length(assigns.changeset.errors) > 0
~H"""
<%= if file_errors_present || input_errors_present do %>
<tr>
<td></td>
<%= if file_errors_present do %>
<td class="alert alert-danger">
<%= for error <- upload_errors(@uploads.files, entry) do %>
<%= error_to_string(error) %>
<% end %>
</td>
<% else %>
<td></td>
<% end %>
<td class="alert alert-danger"><%= error_tag f, :field1 %></td>
<td class="alert alert-danger"><%= error_tag f, :field2 %></td>
<td class="alert alert-danger"><%= error_tag f, :field3 %></td>
<td class="alert alert-danger"><%= error_tag f, :field4 %></td>
<td class="alert alert-danger"><%= error_tag f, :field5 %></td>
<td class="alert alert-danger"><%= error_tag f, :field6 %></td>
<td class="alert alert-danger"><%= error_tag f, :field7 %></td>
<td class="alert alert-danger"><%= error_tag f, :field8 %></td>
</tr>
<tr>
<td class="p-1" colspan="100%"></td>
</tr>
<% end %>
"""
end
What you can notice is that I am trying to list errors for each entry. However, my main problem is that I would have to compare it against multiple changeset results. This is not compatible with form
and I am not sure what would be the best way to proceed about this?
I have come across nested forms with input_for
, however, looking at the Nested model forms with Phoenix LiveView tutorial, it looks like I would have to have database schema designed in a way to have cast_assoc
in there, with has_many
relationship. Since I am just doing an upload action which itself should not be remembered in db, there is no has_many
associacion really.