nested_fields 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc
CHANGED
@@ -1,31 +1,81 @@
|
|
1
1
|
= Nested Fields
|
2
2
|
|
3
|
-
|
3
|
+
An engine designed for generic, dynamic nested forms which may be N>=1 levels deep.
|
4
4
|
|
5
|
-
|
5
|
+
Popular existing solutions for dynamic nested forms in Rails are implemented with javascript rather through controllers, probably because FormBuilders cannot be passed as params.
|
6
6
|
|
7
|
-
It
|
7
|
+
It relies on some {parsing behavior}[http://guides.rubyonrails.org/form_helpers.html] within Rails which may be subject to change.
|
8
|
+
|
9
|
+
It handles both +has_many+ and +has_one+ relationships. For +has_one+, it will allow 0..1 nested associates.
|
8
10
|
|
9
11
|
== Requirements
|
10
12
|
|
11
|
-
|
13
|
+
Rails 3, jQuery
|
14
|
+
|
15
|
+
== Styling
|
12
16
|
|
13
|
-
|
17
|
+
+nested_fields+ is not opinionated with regard to markup. Users are encouraged to provide their own styles.
|
14
18
|
|
15
19
|
== Install
|
16
20
|
|
17
|
-
Add nested_fields to the Gemfile and bundle install.
|
21
|
+
Add +nested_fields+ to the Gemfile and bundle install. The engine's path provides the necessary javascript.
|
22
|
+
|
23
|
+
== Associations
|
24
|
+
|
25
|
+
=== +has_many+
|
26
|
+
|
27
|
+
Each nested +has_many+ association will be bounded by a +fieldset+ with a link to add. Each of its associates will have a link to remove.
|
28
|
+
|
29
|
+
=== +has_one+
|
30
|
+
|
31
|
+
Each nested +has_one+ association will be bounded by a +fieldset+ with a checkbox for toggling the presence of an associate.
|
18
32
|
|
19
33
|
== Usage
|
20
34
|
|
21
35
|
Include 'nested_fields.js' in the layout for the Add and Remove behaviors.
|
22
36
|
|
37
|
+
Declare accepts_nested_attributes_for each association. At present, nested_fields assumes that :allow_destroy is true.
|
38
|
+
|
23
39
|
Use the nested_fields_for helper method.
|
24
|
-
<%= nested_fields_for form_builder, :pluralized_association_name
|
40
|
+
<%= nested_fields_for form_builder, :pluralized_association_name %>
|
41
|
+
|
42
|
+
For example, where f is a the builder for an object which +has_many+ +:associates+
|
43
|
+
<%= nested_fields_for f, :associates %>
|
25
44
|
|
26
45
|
The same type of the form builder argument (e.g. Formtastic, SimpleForm, etc.) will automatically be used for the nested fields.
|
27
46
|
|
28
|
-
|
47
|
+
=== Options
|
48
|
+
|
49
|
+
An optional block can be passed which will be displayed as a header.
|
50
|
+
<% nested_fields_for f, :associates do %>
|
51
|
+
...
|
52
|
+
<% end %>
|
53
|
+
|
54
|
+
==== :nested_partial
|
55
|
+
|
56
|
+
By default, nested_fields will look for a partial in app/views/associates/_fields.html.erb. This can be overridden with the :nested_partial option.
|
57
|
+
<%= nested_fields_for f, :associates, :nested_partial => 'path_to/partial.html.erb' %>
|
58
|
+
|
59
|
+
==== :legend
|
60
|
+
|
61
|
+
By default, nested_fields will provide a +fieldset+ +legend+ with the pluralized, titleized name of the associate class. This can be overriden with the :legend option.
|
62
|
+
<%= nested_fields_for f, :associates, :legend => 'My Title' %>
|
63
|
+
|
64
|
+
==== +:positioned_by+
|
65
|
+
|
66
|
+
The +:positioned_by+ option takes in the name of a field which is used for positioning (e.g. acts_as_list). It will cause the association's +fieldset+ to have the +.positioned+ class and a +data-positioned-by+ attribute with the value.
|
67
|
+
|
68
|
+
A javascript function is provided which sets the values of existing (non-removed) inputs which have id's ending in the value in the order they are displayed.
|
69
|
+
|
70
|
+
repositionNestedFields(nested_fieldset, position_field)
|
71
|
+
|
72
|
+
=== Triggers
|
73
|
+
|
74
|
+
The +nested_fields_changed+ custom event is fired by a nested associate's div after being dynamically added/removed.
|
75
|
+
|
76
|
+
== Example
|
77
|
+
|
78
|
+
Access {demonstration code}[https://github.com/jrmurad/nested_fields-example].
|
29
79
|
|
30
80
|
== Credits
|
31
81
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
@@ -2,7 +2,10 @@
|
|
2
2
|
<a href="#" class="remove_nested_fields">Remove</a>
|
3
3
|
|
4
4
|
<div class="nested_fields_inputs">
|
5
|
-
<%= render
|
6
|
-
|
5
|
+
<%= render :partial => nested_partial,
|
6
|
+
:object => f.object,
|
7
|
+
:as => f.object.class.name.underscore.to_sym,
|
8
|
+
:locals => {:f => f} %>
|
9
|
+
<%= f.hidden_field :_destroy, :class => :nested_fields_destroy %>
|
7
10
|
</div>
|
8
11
|
<% end %>
|
@@ -9,10 +9,13 @@
|
|
9
9
|
Has <%= association.to_s.titleize %>?
|
10
10
|
</label>
|
11
11
|
|
12
|
-
<%= nested_f.hidden_field :_destroy, :class => :destroy_nested_one, :value => local_assigns[:has_zero]
|
12
|
+
<%= nested_f.hidden_field :_destroy, :class => :destroy_nested_one, :value => local_assigns[:has_zero] %>
|
13
13
|
|
14
14
|
<%= content_tag :div, :class => :nested_one, :style => ('display:none' if local_assigns[:has_zero]) do %>
|
15
|
-
<%= render
|
15
|
+
<%= render :partial => nested_partial,
|
16
|
+
:object => nested_f.object,
|
17
|
+
:as => nested_f.object.class.name.underscore.to_sym,
|
18
|
+
:locals => {:f => nested_f} %>
|
16
19
|
<% end %>
|
17
20
|
<% end %>
|
18
21
|
</fieldset>
|
data/nested_fields.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{nested_fields}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.4.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jason Murad"]
|
12
|
-
s.date = %q{2011-02-
|
12
|
+
s.date = %q{2011-02-16}
|
13
13
|
s.description = %q{Unobtrusive dynamic nested forms}
|
14
14
|
s.email = %q{jason@thriess.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -1,49 +1,34 @@
|
|
1
|
-
$(
|
2
|
-
$('.nested_fieldset').each(function(i, nf) {
|
3
|
-
$(nf).trigger('nested_fields_ready');
|
4
|
-
});
|
5
|
-
});
|
6
|
-
|
7
|
-
$('.add_nested_fields').live('click', function() {
|
1
|
+
$('a.add_nested_fields').live('click', function() {
|
8
2
|
$.ajax({
|
9
3
|
context: this,
|
10
4
|
dataType: 'html',
|
11
5
|
url: this.getAttribute('data-url'),
|
12
6
|
success: function(content) {
|
13
7
|
$(this).after(content);
|
14
|
-
$(this).trigger('
|
8
|
+
$(this).trigger('nested_fields_changed');
|
15
9
|
}
|
16
10
|
});
|
17
11
|
|
18
12
|
return false;
|
19
13
|
});
|
20
14
|
|
21
|
-
$('.remove_nested_fields').live('click', function() {
|
22
|
-
$(this).closest('div.nested_fields').find('input[type=hidden]').val('1');
|
23
|
-
$(this).closest('
|
15
|
+
$('a.remove_nested_fields').live('click', function() {
|
16
|
+
$(this).closest('div.nested_fields').hide().find('input[type=hidden].nested_fields_destroy').val('1');
|
17
|
+
$(this).closest('.nested_fieldset').trigger('nested_fields_changed');
|
24
18
|
return false;
|
25
19
|
});
|
26
20
|
|
27
|
-
$('.nested_fields_has_one').live('change', function() {
|
28
|
-
var hidden_field = $(this).closest('.nested_fieldset').find('.destroy_nested_one');
|
29
|
-
$(hidden_field).val($(hidden_field).val() == '
|
30
|
-
$(this).closest('.nested_fieldset')
|
21
|
+
$('input[type=checkbox].nested_fields_has_one').live('change', function() {
|
22
|
+
var hidden_field = $(this).closest('.nested_fieldset').find('input[type=hidden].destroy_nested_one');
|
23
|
+
$(hidden_field).val( $(hidden_field).val() == '' ? 1 : '' );
|
24
|
+
var nfs = $(this).closest('.nested_fieldset')
|
25
|
+
nfs.find('.nested_one').toggle();
|
26
|
+
nfs.trigger('nested_fields_changed')
|
31
27
|
});
|
32
28
|
|
33
|
-
|
34
|
-
|
29
|
+
/* reset position inputs to reflect addition or removal of associates */
|
30
|
+
function repositionNestedFields(nested_fieldset, pos_fld) {
|
31
|
+
$(nested_fieldset).children('.nested_fields:visible').each(function(i, nested_fields) {
|
35
32
|
$(nested_fields).find('input[id$="' + pos_fld + '"]').val(i);
|
36
33
|
});
|
37
34
|
}
|
38
|
-
|
39
|
-
$('fieldset.positioned').live('nested_fields_ready', function() {
|
40
|
-
var pos_fld = this.getAttribute('data-positioned-by');
|
41
|
-
|
42
|
-
if (pos_fld) {
|
43
|
-
reposition(this, pos_fld);
|
44
|
-
|
45
|
-
if (!$(this).hasClass('ui-sortable')) {
|
46
|
-
$(this).sortable({update: function() { reposition(this, pos_fld); }});
|
47
|
-
}
|
48
|
-
}
|
49
|
-
});
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: nested_fields
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.4.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Jason Murad
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-02-
|
13
|
+
date: 2011-02-16 00:00:00 -05:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -98,7 +98,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
98
98
|
requirements:
|
99
99
|
- - ">="
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
hash: -
|
101
|
+
hash: -1830066020513997953
|
102
102
|
segments:
|
103
103
|
- 0
|
104
104
|
version: "0"
|