Skip to content

Commit b5aff53

Browse files
Merge pull request #3 from stimulus-components/feature/remove-field
Adding support to remove field
2 parents 114180e + 35f6017 commit b5aff53

File tree

4 files changed

+76
-18
lines changed

4 files changed

+76
-18
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88

9+
## Changed
10+
11+
- Adding `remove` support.
12+
913
## [1.0.0] - 2020-10-15
1014

1115
### Added

README.md

+22-7
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ To DRY up the code, we extract the fields in a partial called `todo_form` to use
6969

7070
In your view:
7171
```html
72-
<%= form_with model: @user, data: { controller: 'nested-form' } do |f| %>
72+
<%= form_with model: @user, data: { controller: 'nested-form', nested_form_wrapper_selector: '.nested-form-wrapper' } do |f| %>
7373
<template data-target="nested-form.template">
7474
<%= f.fields_for :todos, Todo.new, child_index: 'NEW_RECORD' do |todo_fields| %>
7575
<%= render "todo_form", f: todo_fields %>
@@ -83,22 +83,37 @@ In your view:
8383
<!-- Inserted elements will be injected before that target. -->
8484
<div data-target="nested-form.target"></div>
8585

86-
<button type="button" data-action="click->nested-form#add">
86+
<button type="button" data-action="nested-form#add">
8787
Add todo
8888
</button>
8989

9090
<%= f.submit 'Save todos' %>
9191
<% end %>
9292
```
9393

94-
In the `todo_form.html.erb` partial:
94+
In the `_todo_form.html.erb` partial:
9595
```html
96-
<%= f.label :description %>
97-
<%= f.text_field :description %>
96+
<div class="nested-form-wrapper" data-new-record="<%= f.object.new_record? %>">
97+
<%= f.label :description %>
98+
<%= f.text_field :description %>
99+
100+
<button type="button" data-action="nested-form#remove">
101+
Remove todo
102+
</button>
103+
104+
<%= f.hidden_field :_destroy %>
105+
</div>
98106
```
99107

100-
As explained in the [documentation](https://apidock.com/rails/ActionView/Helpers/FormHelper/fields_for), we need to
101-
specify the `child_index` and replace its value in JavaScript because the index needs to be unique for each fields.
108+
As explained in the [documentation](https://apidock.com/rails/ActionView/Helpers/FormHelper/fields_for), we need to specify the `child_index` and replace its value in JavaScript because the index needs to be unique for each fields.
109+
110+
## Configuration
111+
112+
| Attribute | Default | Description | Optional |
113+
| --------- | ------- | ----------- | -------- |
114+
| `data-nested-form-wrapper-selector` | `.nested-form-wrapper` | Selector to find the wrapper. ||
115+
116+
The remove feature is completely optional.
102117

103118
## Extending Controller
104119

index.html

+33-11
Original file line numberDiff line numberDiff line change
@@ -92,31 +92,53 @@ <h2 class="text-center text-2xl font-bold my-4">Essential links</h2>
9292
</li>
9393
</ul>
9494

95-
<section data-controller="nested-form" class="mt-16">
96-
<form>
95+
<section class="mt-16">
96+
<form data-controller="nested-form">
9797
<template data-target="nested-form.template">
98-
<div class="mt-4">
98+
<div class="mt-4 nested-form-wrapper" data-new-record="true">
9999
<label for="NEW_RECORD" class="block text-sm font-medium leading-5 text-gray-700">New todo</label>
100-
<div class="mt-1 relative rounded-md shadow-sm">
100+
<div class="mt-1 flex relative rounded-md shadow-sm">
101101
<input
102102
id="NEW_RECORD"
103-
name="user[todos][NEW_RECORD][description]"
104-
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
103+
name="user[todos_attributes][NEW_RECORD][description]"
104+
class="appearance-none border w-full py-2 px-3 rounded-l-md text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
105105
placeholder="Your todo"
106106
/>
107+
108+
<button
109+
class="cursor-pointer inline-flex items-center px-3 rounded-r-md border border-l-0 border-gray-300 bg-gray-100 text-gray-500 sm:text-sm"
110+
type="button"
111+
data-action="nested-form#remove"
112+
title="Remove todo"
113+
>
114+
X
115+
</button>
116+
117+
<input type="hidden" name="user[todos_attributes][NEW_RECORD][_destroy]" />
107118
</div>
108119
</div>
109120
</template>
110121

111-
<div class="mt-4">
122+
<div class="mt-4 nested-form-wrapper" data-new-record="false">
112123
<label for="todo-1" class="block text-sm font-medium leading-5 text-gray-700">Your todo</label>
113-
<div class="mt-1 relative rounded-md shadow-sm">
124+
<div class="mt-1 flex relative rounded-md shadow-sm">
114125
<input
115126
id="todo-1"
116-
name="user[todos][0][description]"
117-
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
127+
name="user[todos_attributes][0][description]"
128+
class="appearance-none border w-full py-2 px-3 rounded-l-md text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
118129
value="Pet the cat"
119130
/>
131+
132+
<button
133+
class="cursor-pointer inline-flex items-center px-3 rounded-r-md border border-l-0 border-gray-300 bg-gray-100 text-gray-500 sm:text-sm"
134+
type="button"
135+
data-action="nested-form#remove"
136+
title="Remove todo"
137+
>
138+
X
139+
</button>
140+
141+
<input type="hidden" name="user[todos_attributes][0][_destroy]" />
120142
</div>
121143
</div>
122144

@@ -125,7 +147,7 @@ <h2 class="text-center text-2xl font-bold my-4">Essential links</h2>
125147
<button
126148
id="nested-form-button"
127149
type="button"
128-
data-action="click->nested-form#add"
150+
data-action="nested-form#add"
129151
class="mt-4 bg-white hover:bg-gray-100 text-gray-800 font-semibold py-2 px-4 border border-gray-400 rounded shadow"
130152
>
131153
Add todo

src/index.js

+17
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,27 @@ import { Controller } from 'stimulus'
33
export default class extends Controller {
44
static targets = ['target', 'template']
55

6+
initialize () {
7+
this.wrapperSelector = this.data.get('wrapperSelector') || '.nested-form-wrapper'
8+
}
9+
610
add (e) {
711
e.preventDefault()
812

913
const content = this.templateTarget.innerHTML.replace(/NEW_RECORD/g, new Date().getTime())
1014
this.targetTarget.insertAdjacentHTML('beforebegin', content)
1115
}
16+
17+
remove (e) {
18+
e.preventDefault()
19+
20+
const wrapper = e.target.closest(this.wrapperSelector)
21+
22+
if (wrapper.dataset.newRecord === 'true') {
23+
wrapper.remove()
24+
} else {
25+
wrapper.style.display = 'none'
26+
wrapper.querySelector("input[name*='_destroy']").value = 1
27+
}
28+
}
1229
}

0 commit comments

Comments
 (0)