Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/mamespalmero/dynamic_inputs_for
Dynamically add/remove nested fields to your Phoenix forms
https://github.com/mamespalmero/dynamic_inputs_for
dynamic-forms elixir nested-forms phoenix
Last synced: 3 months ago
JSON representation
Dynamically add/remove nested fields to your Phoenix forms
- Host: GitHub
- URL: https://github.com/mamespalmero/dynamic_inputs_for
- Owner: MamesPalmero
- License: mit
- Created: 2019-09-21T11:09:37.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2020-10-22T16:31:56.000Z (about 4 years ago)
- Last Synced: 2024-10-12T13:23:44.745Z (3 months ago)
- Topics: dynamic-forms, elixir, nested-forms, phoenix
- Language: Elixir
- Homepage:
- Size: 75.2 KB
- Stars: 16
- Watchers: 2
- Forks: 5
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# DynamicInputsFor
Dynamically add/remove nested fields to your Phoenix forms from the client with a
thin JavaScript layer.## Installation
1. The package can be installed by adding `dynamic_inputs_for` to your list of
dependencies in `mix.exs`:```elixir
def deps do
[{:dynamic_inputs_for, "~> 1.1.0"}]
end
```2. Then add `dynamic_inputs_for` to your list of dependencies in `package.json` and
run `npm install`. For the default Phoenix structure, in `assets/package.json`:```json
"dependencies": {
"dynamic_inputs_for": "file:../deps/dynamic_inputs_for"
}
```3. Finally, don't forget to import the module. For the default Phoenix structure, in
`assets/js/app.js`:```js
import "dynamic_inputs_for";
```## Usage example
Imagine the following Ecto schemas:
```elixir
defmodule Shop do
use Ecto.Schemaschema "shops" do
field :name, :string
has_many :products, Product
end
enddefmodule Product do
use Ecto.Schemaschema "products" do
field :name, :string
...belongs_to(:shop, Shop)
end
end
```If you want to be able to dynamically add products in a form, use the
`dynamic_inputs_for` helper in combination with `dynamic_add_button` to generate
the form.If you also want to allow the deletion of nested fields, this library follows the
strategy suggested in the
[Ecto.Changeset](https://hexdocs.pm/ecto/Ecto.Changeset.html) documentation. Add a
separate boolean virtual field to the changeset function that will allow you to
manually mark the associated data for deletion and use the `dynamic_delete_button`
helper inside the function that you pass to `dynamic_inputs_for` to generate a delete
button for each associated data.```elixir
defmodule Product do
use Ecto.Schema
import Ecto.Changesetschema "products" do
field :name, :string
...
field :delete, :boolean, virtual: truebelongs_to(:shop, Shop)
enddef changeset(product, params) do
product
|> cast(params, [:name, :delete])
|> maybe_mark_for_deletion
enddefp maybe_mark_for_deletion(changeset) do
if get_change(changeset, :delete) do
%{changeset | action: :delete}
else
changeset
end
end
end
``````eex
<%= form_for @changeset, Routes.shop_path(@conn, :create), fn f -> %>
<%= text_input f, :name %><%= dynamic_inputs_for f, :products, %Product{}, fn f_product -> %>
<%= text_input f_product, :name %><%= dynamic_delete_button("Delete") %>
<% end%><%= dynamic_add_button :products, "Add" %>
<% end %>
```If you want the new fields to have default values, you can pass them to the schema
you pass to `dynamic_inputs_for`. In the previous example `%Product{name: "ASDF"}`.```eex
<%= dynamic_inputs_for f, :products, %Product{name: "ASDF"}, fn f_product -> %>
```## Custom JavaScript events
When you add or delete an element, the events `dynamic:addedFields` and
`dynamic:deletedFields` are triggered. These events can be listened to modify the
nested fields or integrate them with third party javascript libraries.```js
document.addEventListener(
"dynamic:addedFields",
function(e) {
e.target.style.backgroundColor = "red";
},
false
);
```or if you use jQuery
```js
$(document).on("dynamic:addedFields", e => {
e.target.style.backgroundColor = "red";
});
```