cool_nested_forms 2.0.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +70 -34
- data/app/helpers/cool_nested_forms_helper.rb +41 -1
- data/lib/cool_nested_forms/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e5c86ef0d5b6bba5a5ed6ab919a29b88fea57e8d
|
|
4
|
+
data.tar.gz: 65c68db81d44c1ae8d4060383ee9edc9b0fe54d8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 03bc77c8616c95989925cfef00ebe501ca63d132adb92b4313115225c3341c73c8577a46b96fa0d2e2ac32cd50badae248cf851361f91394e03c86de49032f41
|
|
7
|
+
data.tar.gz: 966e9e3ed104dfab84f5e6b50ccdf6a6a2267262a94418409368563a5707335c2ddd2d99d2c384c879558b1a945a186b014b4af6503e28f6f4ae0879e1ef5d08
|
data/README.md
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
# CoolNestedForms
|
|
2
2
|
[](https://badge.fury.io/rb/cool_nested_forms)
|
|
3
3
|
|
|
4
|
-
Add
|
|
5
|
-
For example a
|
|
6
|
-
|
|
4
|
+
Add dynamically generated forms to your model's form for any of its associations.
|
|
5
|
+
For example if you have a Job model that has_many Task then this gem will assist you in adding
|
|
6
|
+
all the JavaScript necessary to allow your users to click an "Add Task" button on your edit view,
|
|
7
|
+
the view will then append a new form to the DOM with all the field attributes formatted for
|
|
8
|
+
rails (id, name, etc) plus will add any necessary hidden fields for existing records (task.id).
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
There is also JS events raised when an entry is added or removed so you can hook up your code for
|
|
11
|
+
pre-form submission editing.
|
|
12
|
+
|
|
13
|
+
Any entries added or removed won't update the DB until the form is submitted.
|
|
9
14
|
|
|
10
15
|
## Installation
|
|
11
16
|
|
|
@@ -23,7 +28,7 @@ Or install it yourself as:
|
|
|
23
28
|
|
|
24
29
|
$ gem install cool_nested_forms
|
|
25
30
|
|
|
26
|
-
Then require the
|
|
31
|
+
Then require the JavaScript in your app/assets/javascripts/application.js
|
|
27
32
|
```javascript
|
|
28
33
|
//= require cool_nested_forms
|
|
29
34
|
```
|
|
@@ -35,22 +40,25 @@ For this example I will use Job and Task models
|
|
|
35
40
|
|
|
36
41
|
#### Job Model
|
|
37
42
|
```ruby
|
|
38
|
-
class Job <
|
|
43
|
+
class Job < ApplicationRecord
|
|
39
44
|
has_many :tasks, :dependent => :destroy
|
|
40
|
-
#
|
|
45
|
+
# we need to accepts_nested_attributes_for Task
|
|
46
|
+
# :name is required in this example - Use your own required field here or remove the reject_if call
|
|
47
|
+
# :allow_destroy => true so we can delete entries when passing the _destroy field
|
|
41
48
|
accepts_nested_attributes_for :tasks, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
|
|
42
49
|
end
|
|
43
50
|
```
|
|
44
51
|
#### Task Model
|
|
45
52
|
```ruby
|
|
46
|
-
class Task <
|
|
53
|
+
class Task < ApplicationRecord
|
|
47
54
|
belongs_to :job
|
|
48
55
|
end
|
|
49
56
|
```
|
|
50
57
|
### Preparing the Job Controller
|
|
51
58
|
```ruby
|
|
52
59
|
class JobsController < ApplicationController
|
|
53
|
-
|
|
60
|
+
# include the CoolNestedFormsHelper
|
|
61
|
+
helper CoolNestedFormsHelper
|
|
54
62
|
# other code #
|
|
55
63
|
|
|
56
64
|
def job_params
|
|
@@ -60,47 +68,75 @@ class JobsController < ApplicationController
|
|
|
60
68
|
end
|
|
61
69
|
end
|
|
62
70
|
```
|
|
63
|
-
### The
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
### The partials used to generate the new and existing tasks
|
|
72
|
+
We need to provide cool_nested_forms two partials. One for existing records and one
|
|
73
|
+
for existing records. They will be placed under the Job's view folder. Make sure the
|
|
74
|
+
id field of the container is set like so: id="<%= id %>"
|
|
75
|
+
|
|
76
|
+
app/views/jobs/_task_new.html.rb
|
|
77
|
+
```erb
|
|
78
|
+
<!-- the id is generated from the helper methods using this template so always include it like so -->
|
|
79
|
+
<div id="<%= id %>">
|
|
80
|
+
<!-- _destroy field: used for removing the record -->
|
|
81
|
+
<%= builder.hidden_field :_destroy, :class => 'cnf-removable' %>
|
|
82
|
+
|
|
83
|
+
<!-- data to be collected -->
|
|
84
|
+
<%= builder.label :name %>
|
|
85
|
+
<%= builder.text_field :name %>
|
|
86
|
+
|
|
87
|
+
<!-- the remove button. make sure to pass the id as target or
|
|
88
|
+
it will default to the parent DOM element when removing the item -->
|
|
89
|
+
<%= remove_entry_button "Remove", Task, {:target => id} %>
|
|
90
|
+
</div>
|
|
91
|
+
```
|
|
92
|
+
app/views/jobs/_task_edit.html.rb
|
|
93
|
+
```erb
|
|
94
|
+
<!-- the id is generated from the helper methods using this template so always include it like so -->
|
|
95
|
+
<div id="<%= id %>">
|
|
96
|
+
<!-- _destroy field: used for removing the record -->
|
|
97
|
+
<%= builder.hidden_field :_destroy, :class => 'cnf-removable' %>
|
|
98
|
+
<%= builder.hidden_field :id %> <!-- keeps the id inside this div -->
|
|
99
|
+
|
|
100
|
+
<!-- data to be edited -->
|
|
101
|
+
<%= builder.label :name %>
|
|
102
|
+
<%= builder.text_field :name %>
|
|
103
|
+
<!-- Note: if you not wish for your users to edit this field after it is added
|
|
104
|
+
you could just display the content. -->
|
|
105
|
+
|
|
106
|
+
<!-- the remove button. make sure to pass the id as target or
|
|
107
|
+
it will default to the parent DOM element when removing the item -->
|
|
108
|
+
<%= remove_entry_button "Remove", Task, {:target => id} %>
|
|
73
109
|
</div>
|
|
74
110
|
```
|
|
75
111
|
|
|
76
112
|
## Adding functionality to the Job form
|
|
77
113
|
app/views/jobs/_form.html.erb
|
|
78
|
-
```
|
|
79
|
-
<%=
|
|
80
|
-
|
|
114
|
+
```erb
|
|
115
|
+
<%= form_with(model: job, local: true) do |form| %>
|
|
81
116
|
|
|
82
117
|
<!-- your other job fields go here -->
|
|
83
118
|
|
|
119
|
+
<!-- this generates a template for JavaScript. Pass the Task model class here. -->
|
|
120
|
+
<%= new_entry_template(form,Task) %>
|
|
84
121
|
|
|
85
|
-
<!-- this generates a
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
<%= add_child_button "Add Task", :tasks, "tasks_#{f.object.id}", "tasks_#{f.object.id}", "<your-css-classes>" %>
|
|
122
|
+
<!-- this generates a button that adds a task into <div id="tasks">. id="tasks"
|
|
123
|
+
is automatically generated by the next helper by convention. Pass the Task model class here. -->
|
|
124
|
+
<%= new_entry_button("Add Task", Task )%>
|
|
89
125
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
</div>
|
|
126
|
+
<!-- generates a container with any existing tasks. provides a location for
|
|
127
|
+
placing new tasks. The id of the container is by default <div id="tasks">
|
|
128
|
+
(the association plural form). Pass the Task model class here. -->
|
|
129
|
+
<%= entries_container(form,Task,job.tasks) %>
|
|
95
130
|
|
|
96
131
|
<%end%>
|
|
97
132
|
```
|
|
98
133
|
|
|
99
134
|
### After add/remove events
|
|
100
|
-
If you need to perform any other javascript actions after
|
|
135
|
+
If you need to perform any other javascript actions after an entry is added or
|
|
136
|
+
removed, you can add a listener to these events
|
|
101
137
|
```javascript
|
|
102
|
-
coolNestedForms.
|
|
103
|
-
coolNestedForms.
|
|
138
|
+
coolNestedForms.entryAdded
|
|
139
|
+
coolNestedForms.entryRemoved
|
|
104
140
|
```
|
|
105
141
|
Something like this
|
|
106
142
|
```javascript
|
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
module CoolNestedFormsHelper
|
|
2
|
+
## entries_container ##
|
|
3
|
+
# arguments
|
|
4
|
+
# - builder: a FormBuilder Object obtained from form_with or form_for
|
|
5
|
+
# - association: a model class i.e. MyTask
|
|
6
|
+
# - current_entries: all the current entries for the parent i.e. a Form.tasks
|
|
7
|
+
# - options: hash of override options
|
|
8
|
+
# - partial: name of the erb partial to use as a tempalte for the existing entries
|
|
9
|
+
# - id: ID to be used in for the container
|
|
10
|
+
# - plurilized: the plural version of the model name
|
|
11
|
+
# - singularized: the singular version of the model name
|
|
12
|
+
# - parent_singularized: the name of the parent record. used for generating the entry's container id
|
|
13
|
+
# - parent_id: the id of the parent record. used for generating the entry's container id
|
|
14
|
+
# - class: a string with any css class names to be used for styling
|
|
15
|
+
# - style: a string with any css styles
|
|
16
|
+
# - tag: override the returned tag
|
|
17
|
+
def entries_container(builder,association,current_entries, options = {})
|
|
18
|
+
# initialize options
|
|
19
|
+
options[:partial] ||= "#{association.name.underscore}_edit"
|
|
20
|
+
options[:id] ||= association.name.underscore.pluralize
|
|
21
|
+
options[:pluralized] ||= association.name.underscore.pluralize
|
|
22
|
+
options[:singularized] ||= association.name.underscore
|
|
23
|
+
options[:parent_singularized] ||= builder.object.class.name.underscore
|
|
24
|
+
options[:parent_id] ||= builder.object.id.to_s
|
|
25
|
+
options[:class] ||= ''
|
|
26
|
+
options[:style] ||= ''
|
|
27
|
+
options[:tag] ||= :div
|
|
28
|
+
|
|
29
|
+
# render all the current entries
|
|
30
|
+
output = builder.fields_for(options[:pluralized], current_entries) do |assoc_builder|
|
|
31
|
+
id = "#{options[:parent_singularized]}_#{options[:parent_id]}_#{options[:singularized]}_#{assoc_builder.object.id}"
|
|
32
|
+
render options[:partial], :builder => assoc_builder, :id => id
|
|
33
|
+
end
|
|
2
34
|
|
|
35
|
+
return content_tag(
|
|
36
|
+
options[:tag],
|
|
37
|
+
output.html_safe,
|
|
38
|
+
:style => options[:style],
|
|
39
|
+
:class => options[:class],
|
|
40
|
+
:id => options[:id]
|
|
41
|
+
)
|
|
42
|
+
end
|
|
3
43
|
## new_entry_template ##
|
|
4
44
|
# arguments
|
|
5
45
|
# - builder: a FormBuilder Object obtained from form_with or form_for
|
|
@@ -12,7 +52,7 @@ module CoolNestedFormsHelper
|
|
|
12
52
|
# - children: an array with childre association options for nested association of a nested association
|
|
13
53
|
def new_entry_template(builder,association, options = {})
|
|
14
54
|
# initialize options
|
|
15
|
-
options[:partial] ||= association.name.underscore
|
|
55
|
+
options[:partial] ||= "#{association.name.underscore}_new"
|
|
16
56
|
options[:id] ||= "#{association.name.underscore}_[tempid]"
|
|
17
57
|
options[:pluralized] ||= association.name.underscore.pluralize
|
|
18
58
|
options[:js_template_name] ||= association.name.underscore.pluralize
|