# `MishkaCmsCoreWeb.Forms.ComponentSubmit`
[🔗](https://github.com/mishka-group/mishka_cms_core/blob/v0.0.1/lib/mishka_cms_core_web/forms/component_submit.ex#L5)

The submit handler for a component's form — the inspector's Configuration tab and the builder's
Interface tab are both this form.

It keeps what the form cannot show. A component's `attrs` and `slots` are declarations, and the
form draws each one's options as a few controls — Required, Default, Doc. A declaration holds more
than that, and holds values those controls cannot draw:

  * keys with no control at all — `values`, `editor`, `default_struct`, a slot's `validate_attrs`;
  * values a text box draws as nothing — `nil`, `false`, `true`, `[]` — or as a string — `0`,
    `1.0`.

Saved as the controls sent them back, a save rewrote the declaration from what was on screen. A
rename of `chelekom-button` declared `attr :type` with no default, and the first page that left
`type` unset raised `key :type not found`.

So once `MishkaGervaz.Form.Web.Events.SubmitHandler.Default` has parsed the params, every row
named like a row the record already declares gets back what the form did not change:

  * in an option map (a `:key_map` sub-field), each key with no control, and each key whose control
    came back exactly as it was drawn;
  * in a list of rows (a `:key_list` sub-field — a slot's own attributes), each row that came back
    exactly as it was drawn, whole. Those rows are drawn flat while the record keeps `required` and
    `doc` under `opts`, and half of one would say both.

Which fields and keys those are is read from the form's own declaration. A control the author did
change is theirs, a blank included; a row they renamed or added is new.

# `after_save`

```elixir
@spec after_save(
  MishkaGervaz.Form.Web.State.t(),
  struct(),
  Phoenix.LiveView.Socket.t()
) ::
  Phoenix.LiveView.Socket.t()
```

Handle post-save logic.

Sends `{:form_saved, mode, record}` to the parent LiveView and runs the `after_save` JS hook.
An update save on a form mounted with a `record_id` assign reloads the saved record for
editing; every other save returns the form to an empty create form.

# `consume_and_merge_uploads`

```elixir
@spec consume_and_merge_uploads(
  MishkaGervaz.Form.Web.State.t(),
  map(),
  Phoenix.LiveView.Socket.t()
) ::
  {Phoenix.LiveView.Socket.t(), map()}
```

# `submit`

```elixir
@spec submit(MishkaGervaz.Form.Web.State.t(), map(), Phoenix.LiveView.Socket.t()) ::
  Phoenix.LiveView.Socket.t()
```

Submit the form for create or update.

Submits the AshPhoenix.Form and handles success/error.
Consumes uploaded files and merges them into params before submission.

# `transform_params`

```elixir
@spec transform_params(MishkaGervaz.Form.Web.State.t(), map()) :: map()
```

Transform params before submission.

Override this to add computed fields, strip unwanted params, etc.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
