BLacika

BLacika

Hi!
I would like to ask for help. I have a form and I would like to change the values of some fields if I change one of them.
For example, I have this code snippet:

@impl true
  def handle_event("validate", %{"_target" => ["invoice", "date"], "invoice" => invoice_params}, socket) do
    %{"date" => date} = invoice_params
    invoice = %{
      socket.assigns.invoice
      | due_date: Date.add(Date.from_iso8601!(date), socket.assigns.invoice.payment_term),
        date: Date.from_iso8601!(date)
    }

    changeset =
      invoice
      |> Invoices.change_invoice(invoice_params)
      |> Ecto.Changeset.put_assoc(:invoice_lines, invoice.invoice_lines)
      |> Map.put(:action, :validate)

    {:noreply,
     socket
     |> assign(:invoice, invoice)
     |> assign(:changeset, changeset)}
  end

I want to update the due_date field. But this does not change the field in the form.
I’ve manually updated the socket.assigns.invoice, it doesn’t work either.

I have a partner field which works though. When I select a partner, it goes through a few updates. The problem there is that the validation on the other field (date) does not work. Here is the code for that:

@impl true
 def handle_event(
     "validate",
     %{"_target" => ["invoice", "partner_id"], "invoice" => %{"partner_id" => partner_id}} = invoice_params,
     socket) when partner_id != "" do
   partner = Partners.get_partner!(partner_id) |> Repo.preload([:bank_accounts])
   invoice = %{
     socket.assigns.invoice
     | partner_id: partner.id,
       payment_method: partner.payment_method,
       payment_term: partner.payment_term,
       currency_id: partner.currency_id,
       due_date: Date.add(socket.assigns.invoice.date, partner.payment_term),
       exchange_rate: exchange_rate(partner.currency_id)
   }
   changeset = invoice_changeset(invoice, invoice_params) |> Map.put(:action, :validate)

   {:noreply,
    socket
    |> assign(:partner, partner)
    |> assign(:invoice, invoice)
    |> assign(:partner, partner)
    |> assign(:changeset, changeset)
    |> assign(:bank_accounts, bank_accounts(partner.bank_accounts))}
 end

Is there anything in the documentation about this, or perhaps an example? I have not found anything similar here on the forum. Thank you! :slight_smile:

Showing Posts 1 to 10

codeanpeace

codeanpeace

Hmm, what does your HEEX code look like?

And as a sanity check, could you add an IO.inspect(changeset, label: "changeset: ") and post the console output? It also might be worth setting liveSocket.enableDebug() and sharign what comes through in your browser’s developer console.

trisolaran

trisolaran

This might be a long shot, but could it be that the element in the form whose value you want to update is the one having focus? Because in that case LiveView would never overwrite the value entered by the user.

BLacika

BLacika OP

Hi!
When i change partner which affect other fields:

Parameters: %{"_target" => ["invoice", "partner_id"], "invoice" => %{"currency_id" => "9425c106-1504-4ae5-a4f0-4dba1f10ae1f", "date" => "2023-03-06", "delivery_date" => "2023-03-06", "due_date" => "2023-03-06", "exchange_rate" => "1.0", "partner_id" => "2055bf2d-dd76-49be-ab93-b9837e184480", "payment_method" => "transfer", "payment_term" => "0"}}

changeset: #Ecto.Changeset<action: :validate, changes: %{}, errors: [],
 data: #Invoicer.Invoice.Invoices.Invoice<>, valid?: true>

Brower console:

{
    "3": {
        "1": {
            "0": {
                "0": " method=\"post\" errors=\"\" id=\"invoice-form\" phx-change=\"validate\" phx-submit=\"save\"",
                "1": "",
                "2": "",
                "3": {
                    "0": {
                        "2": {
                            "0": " phx-feedback-for=\"invoice[partner_id]\"",
                            "1": {
                                "0": " for=\"invoice-form_partner_id\"",
                                "1": {
                                    "0": "Partner"
                                }
                            },
                            "2": " id=\"invoice-form_partner_id\"",
                            "3": " name=\"invoice[partner_id]\"",
                            "5": "",
                            "7": "<option value=\"\"></option><option selected value=\"2055bf2d-dd76-49be-ab93-b9837e184480\">Székely Kft.</option>",
                            "8": ""
                        },
                        "3": {
                            "0": {
                                "0": " phx-feedback-for=\"invoice[bank_account_id]\"",
                                "1": {
                                    "0": " for=\"invoice-form_bank_account_id\"",
                                    "1": {
                                        "0": "Bank",
                                        "s": [
                                            "\n    <span class=\"label-text\">\n      ",
                                            "\n    </span>\n  "
                                        ]
                                    },
                                    "s": [
                                        "<label",
                                        " class=\"label\">\n  ",
                                        "\n</label>"
                                    ]
                                },
                                "2": " id=\"invoice-form_bank_account_id\"",
                                "3": " name=\"invoice[bank_account_id]\"",
                                "4": "",
                                "5": "",
                                "6": "",
                                "7": "<option value=\"bc830162-9b9c-4ba5-a0e7-4a4a8dd414af\">KH Bank Zrt.</option>",
                                "8": "",
                                "s": [
                                    "<div",
                                    ">\n  ",
                                    "\n  <select",
                                    "",
                                    " class=\"select select-primary w-full p-2 focus:ring-0 focus:border-primary active:ring-0\"",
                                    "",
                                    ">\n    ",
                                    "\n    ",
                                    "\n  </select>\n  ",
                                    "\n</div>"
                                ]
                            },
                            "s": [
                                "",
                                ""
                            ]
                        },
                        "4": {
                            "0": " phx-feedback-for=\"invoice[currency_id]\"",
                            "1": {
                                "0": " for=\"invoice-form_currency_id\"",
                                "1": {
                                    "0": "Currency"
                                }
                            },
                            "2": " id=\"invoice-form_currency_id\"",
                            "3": " name=\"invoice[currency_id]\"",
                            "5": "",
                            "7": "<option selected value=\"9425c106-1504-4ae5-a4f0-4dba1f10ae1f\">Forint</option><option value=\"427e12b0-a581-4456-8a3c-4ba895d83f8a\">Euro</option>",
                            "8": ""
                        },
                        "5": {
                            "0": " phx-feedback-for=\"invoice[exchange_rate]\"",
                            "1": {
                                "0": " for=\"invoice-form_exchange_rate\"",
                                "1": {
                                    "0": "Rate"
                                }
                            },
                            "2": " type=\"number\"",
                            "3": " name=\"invoice[exchange_rate]\"",
                            "4": " id=\"invoice-form_exchange_rate\"",
                            "5": " value=\"1\"",
                            "6": "input-bordered input-primary focus:border-primary input w-full focus:ring-0",
                            "7": " step=\"any\"",
                            "8": ""
                        },
                        "6": {
                            "0": " phx-feedback-for=\"invoice[date]\"",
                            "1": {
                                "0": " for=\"invoice-form_date\"",
                                "1": {
                                    "0": "Date"
                                }
                            },
                            "2": " type=\"date\"",
                            "3": " name=\"invoice[date]\"",
                            "4": " id=\"invoice-form_date\"",
                            "5": " value=\"2023-03-06\"",
                            "6": "input-bordered input-primary focus:border-primary input w-full focus:ring-0",
                            "7": "",
                            "8": ""
                        },
                        "7": {
                            "0": " phx-feedback-for=\"invoice[delivery_date]\"",
                            "1": {
                                "0": " for=\"invoice-form_delivery_date\"",
                                "1": {
                                    "0": "Delivery Date"
                                }
                            },
                            "2": " type=\"date\"",
                            "3": " name=\"invoice[delivery_date]\"",
                            "4": " id=\"invoice-form_delivery_date\"",
                            "5": " value=\"2023-03-06\"",
                            "6": "input-bordered input-primary focus:border-primary input w-full focus:ring-0",
                            "7": "",
                            "8": ""
                        },
                        "8": {
                            "0": " phx-feedback-for=\"invoice[payment_term]\"",
                            "1": {
                                "0": " for=\"invoice-form_payment_term\"",
                                "1": {
                                    "0": "Payment Term"
                                }
                            },
                            "2": " type=\"number\"",
                            "3": " name=\"invoice[payment_term]\"",
                            "4": " id=\"invoice-form_payment_term\"",
                            "5": " value=\"30\"",
                            "6": "input-bordered input-primary focus:border-primary input w-full focus:ring-0",
                            "7": " min=\"0\" step=\"1\"",
                            "8": ""
                        },
                        "9": {
                            "0": " phx-feedback-for=\"invoice[due_date]\"",
                            "1": {
                                "0": " for=\"invoice-form_due_date\"",
                                "1": {
                                    "0": "Due Date"
                                }
                            },
                            "2": " type=\"date\"",
                            "3": " name=\"invoice[due_date]\"",
                            "4": " id=\"invoice-form_due_date\"",
                            "5": " value=\"2023-04-05\"",
                            "6": "input-bordered input-primary focus:border-primary input w-full focus:ring-0",
                            "7": "",
                            "8": ""
                        },
                        "10": {
                            "0": " phx-feedback-for=\"invoice[payment_method]\"",
                            "1": {
                                "0": " for=\"invoice-form_payment_method\"",
                                "1": {
                                    "0": "Payment Method"
                                }
                            },
                            "2": " id=\"invoice-form_payment_method\"",
                            "3": " name=\"invoice[payment_method]\"",
                            "5": "",
                            "7": "<option selected value=\"transfer\">transfer</option><option value=\"credit\">credit</option><option value=\"card\">card</option><option value=\"cash\">cash</option><option value=\"voucher\">voucher</option>",
                            "8": ""
                        },
                        "11": ""
                    },
                    "1": ""
                }
            }
        }
    }
}

When i change date which doesn’t work:

Parameters: %{"_target" => ["invoice", "date"], "invoice" => %{"bank_account_id" => "bc830162-9b9c-4ba5-a0e7-4a4a8dd414af", "currency_id" => "9425c106-1504-4ae5-a4f0-4dba1f10ae1f", "date" => "2023-03-07", "delivery_date" => "2023-03-06", "due_date" => "2023-04-05", "exchange_rate" => "1", "partner_id" => "2055bf2d-dd76-49be-ab93-b9837e184480", "payment_method" => "transfer", "payment_term" => "30"}}
changeset: #Ecto.Changeset<
  action: :validate,
  changes: %{
    bank_account_id: "bc830162-9b9c-4ba5-a0e7-4a4a8dd414af",
    due_date: ~D[2023-04-05],
    exchange_rate: 1.0
  },
  errors: [],
  data: #Invoicer.Invoice.Invoices.Invoice<>,
  valid?: true

Browser console:

{
    "3": {
        "1": {
            "0": {
                "0": " method=\"post\" errors=\"\" id=\"invoice-form\" phx-change=\"validate\" phx-submit=\"save\"",
                "1": "",
                "2": "",
                "3": {
                    "0": {
                        "2": {
                            "0": " phx-feedback-for=\"invoice[partner_id]\"",
                            "1": {
                                "0": " for=\"invoice-form_partner_id\"",
                                "1": {
                                    "0": "Partner"
                                }
                            },
                            "2": " id=\"invoice-form_partner_id\"",
                            "3": " name=\"invoice[partner_id]\"",
                            "5": "",
                            "7": "<option selected value=\"\"></option><option value=\"2055bf2d-dd76-49be-ab93-b9837e184480\">Székely Kft.</option>",
                            "8": {
                                "d": [
                                    [
                                        {
                                            "0": {
                                                "0": {
                                                    "0": " aria-hidden=\"true\" class=\"mt-0.5 h-5 w-5 flex-none fill-rose-500\" fill=\"currentColor\" viewBox=\"0 0 20 20\"",
                                                    "1": {
                                                        "0": "<path fill-rule=\"evenodd\" d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z\" clip-rule=\"evenodd\"/>",
                                                        "s": 0
                                                    },
                                                    "s": 1
                                                },
                                                "s": 2
                                            },
                                            "1": {
                                                "0": "can&#39;t be blank",
                                                "s": 3
                                            },
                                            "s": 4
                                        }
                                    ]
                                ],
                                "p": {
                                    "0": [
                                        "",
                                        ""
                                    ],
                                    "1": [
                                        "<svg xmlns=\"http://www.w3.org/2000/svg\"",
                                        ">\n  ",
                                        "\n</svg>"
                                    ],
                                    "2": [
                                        "",
                                        ""
                                    ],
                                    "3": [
                                        "",
                                        ""
                                    ],
                                    "4": [
                                        "<p class=\"phx-no-feedback:hidden mt-3 flex gap-3 text-sm leading-6 text-rose-600\">\n  ",
                                        "\n  ",
                                        "\n</p>"
                                    ]
                                },
                                "s": [
                                    "",
                                    ""
                                ]
                            }
                        },
                        "3": "",
                        "4": {
                            "0": " phx-feedback-for=\"invoice[currency_id]\"",
                            "1": {
                                "0": " for=\"invoice-form_currency_id\"",
                                "1": {
                                    "0": "Currency"
                                }
                            },
                            "2": " id=\"invoice-form_currency_id\"",
                            "3": " name=\"invoice[currency_id]\"",
                            "5": "",
                            "7": "<option selected value=\"9425c106-1504-4ae5-a4f0-4dba1f10ae1f\">Forint</option><option value=\"427e12b0-a581-4456-8a3c-4ba895d83f8a\">Euro</option>",
                            "8": ""
                        },
                        "5": {
                            "0": " phx-feedback-for=\"invoice[exchange_rate]\"",
                            "1": {
                                "0": " for=\"invoice-form_exchange_rate\"",
                                "1": {
                                    "0": "Rate"
                                }
                            },
                            "2": " type=\"number\"",
                            "3": " name=\"invoice[exchange_rate]\"",
                            "4": " id=\"invoice-form_exchange_rate\"",
                            "5": " value=\"1.0\"",
                            "6": "input-bordered input-primary focus:border-primary input w-full focus:ring-0",
                            "7": " step=\"any\"",
                            "8": ""
                        },
                        "6": {
                            "0": " phx-feedback-for=\"invoice[date]\"",
                            "1": {
                                "0": " for=\"invoice-form_date\"",
                                "1": {
                                    "0": "Date"
                                }
                            },
                            "2": " type=\"date\"",
                            "3": " name=\"invoice[date]\"",
                            "4": " id=\"invoice-form_date\"",
                            "5": " value=\"2023-03-07\"",
                            "6": "input-bordered input-primary focus:border-primary input w-full focus:ring-0",
                            "7": "",
                            "8": ""
                        },
                        "7": {
                            "0": " phx-feedback-for=\"invoice[delivery_date]\"",
                            "1": {
                                "0": " for=\"invoice-form_delivery_date\"",
                                "1": {
                                    "0": "Delivery Date"
                                }
                            },
                            "2": " type=\"date\"",
                            "3": " name=\"invoice[delivery_date]\"",
                            "4": " id=\"invoice-form_delivery_date\"",
                            "5": " value=\"2023-03-06\"",
                            "6": "input-bordered input-primary focus:border-primary input w-full focus:ring-0",
                            "7": "",
                            "8": ""
                        },
                        "8": {
                            "0": " phx-feedback-for=\"invoice[payment_term]\"",
                            "1": {
                                "0": " for=\"invoice-form_payment_term\"",
                                "1": {
                                    "0": "Payment Term"
                                }
                            },
                            "2": " type=\"number\"",
                            "3": " name=\"invoice[payment_term]\"",
                            "4": " id=\"invoice-form_payment_term\"",
                            "5": " value=\"0\"",
                            "6": "input-bordered input-primary focus:border-primary input w-full focus:ring-0",
                            "7": " min=\"0\" step=\"1\"",
                            "8": ""
                        },
                        "9": {
                            "0": " phx-feedback-for=\"invoice[due_date]\"",
                            "1": {
                                "0": " for=\"invoice-form_due_date\"",
                                "1": {
                                    "0": "Due Date"
                                }
                            },
                            "2": " type=\"date\"",
                            "3": " name=\"invoice[due_date]\"",
                            "4": " id=\"invoice-form_due_date\"",
                            "5": " value=\"2023-03-06\"",
                            "6": "input-bordered input-primary focus:border-primary input w-full focus:ring-0",
                            "7": "",
                            "8": ""
                        },
                        "10": {
                            "0": " phx-feedback-for=\"invoice[payment_method]\"",
                            "1": {
                                "0": " for=\"invoice-form_payment_method\"",
                                "1": {
                                    "0": "Payment Method"
                                }
                            },
                            "2": " id=\"invoice-form_payment_method\"",
                            "3": " name=\"invoice[payment_method]\"",
                            "5": "",
                            "7": "<option selected value=\"transfer\">transfer</option><option value=\"credit\">credit</option><option value=\"card\">card</option><option value=\"cash\">cash</option><option value=\"voucher\">voucher</option>",
                            "8": ""
                        },
                        "11": ""
                    },
                    "1": ""
                }
            }
        }
    }
}

Which may also be interesting is i don’t assign starter invoice datas in mount, but in apply action, because i use this form inside a liveview, and later i would like to use this liveview as edit mode:

defp apply_action(socket, :new, _params) do
    today = Date.utc_today()
    invoice = %Invoice{
      name: "Draft",
      date: today,
      delivery_date: today,
      due_date: today,
      notes: "",
      state: "new",
      payment_term: 0,
      invoice_lines: []
    }
    changeset =
      invoice
      |> Invoices.change_invoice(%{})
      |> Ecto.Changeset.put_assoc(:invoice_lines, invoice.invoice_lines)

    socket
    |> assign(:page_title, "New Invoice")
    |> assign(:invoice, invoice)
    |> assign(:changeset, changeset)
  end
BLacika

BLacika OP

No. I’ve been watching this on purpose.

codeanpeace

codeanpeace

Is the invoice_changeset function doing something different in the working partner validate callback compared to the date validate callback? Also, what’s the reasoning behind the put_assoc here? invoice.invoice_lines is coming straight from the socket assigns and not the event data.

codeanpeace

codeanpeace

Ahh, I think you may be overwriting the due date in your callback function.

The form’s current due_date is being sent back in the parameters nested under "invoice".

This means that the invoice_params from the callback function head includes the "due_date" coming from the form. Assuming Invoices.change_invoice/2 function is pretty standard, the form’s "due_date" in the invoice_params will replace the due_date in the invoice struct that you calculated and defined in the function itself.

BLacika

BLacika OP

Thank you very much for your help and guidance. You helped a lot :slight_smile: It finally helped me to find out where I went wrong. Basically, I should have read the documentation better :smiley: The thing is, I thought that socket.assigns.invoice reflected the state of the form and I started to update it. I rewrote the code and now I update the params fields from the form and compile the changeset that way. So now it works as I had intended.

Like here:

@impl true
  def handle_event("validate", %{"_target" => ["invoice", "date"], "invoice" => invoice_params}, socket) do
    %{"date" => date, "payment_term" => payment_term} = invoice_params
    invoice_params =
      invoice_params
      |> Map.put("due_date", Date.add(Date.from_iso8601!(date), String.to_integer(payment_term)))
      |> Map.put("date", Date.from_iso8601!(date))

    changeset =
      socket.assigns.invoice
      |> Invoices.change_invoice(invoice_params)
      |> Ecto.Changeset.put_assoc(:invoice_lines, socket.assigns.invoice.invoice_lines)
      |> Map.put(:action, :validate)

    socket =
      socket
      |> assign(:changeset, changeset)

    {:noreply, socket}
  end
codeanpeace

codeanpeace

Glad to hear it helped!

Yeah, I did wonder why you were updating a db resource in the socket assigns since that usually only happens after a successful database insert/update/destroy operation. Like you’ve already figured out, it’s the changeset in the socket assigns that’s meant to reflect the state of the form.

Just curious, what’s the intention behind this line? Is this a multi stage form where the associated invoice lines don’t appear until after a valid date is selected?

BLacika

BLacika OP

Nope. The invoice has a has_many relationship with invoice_line schema. I managed the implement a handle_event that add new invoice_lines to the invoice. And i don’t know even if this line should be here, because i thought that every time i update the changeset, i should use put_assoc as well. And this line should also be fixed, because i think here should be invoice_params[“invoice_lines”]. But am I correct that I only need to apply this if the change affects the invoice_line array? :slight_smile:

codeanpeace

codeanpeace

You can definitely use a changeset without put_assoc when you’re just working with the parent resource. If the form that’s connected to this validation event doesn’t have fields for the associations, which is suggested because that line pulls the invoice_lines off the socket rather than the params, I suspect that the put_assoc line isn’t necessary.

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews