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
- nested_fields is an Engine designed for generic, dynamic nested forms which may be N>=1 levels deep.
3
+ An engine designed for generic, dynamic nested forms which may be N>=1 levels deep.
4
4
 
5
- Of what I could find, the existing solutions for dynamic nested forms in Rails are implemented with javascript rather through Controllers. It is my understanding that this is because FormBuilders cannot be passed as params to Controllers.
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 does rely on some {parsing behavior}[http://guides.rubyonrails.org/form_helpers.html] within Rails which may or may not be intended for use in this manner.
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
- Designed for Rails 3 applications.
13
+ Rails 3, jQuery
14
+
15
+ == Styling
12
16
 
13
- jQuery is required. In the future, this requirement could be removed without much difficulty.
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, 'path_to/inner_partial' %>
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
- The <tt>nested_fields_ready</tt> custom event is fired after a nested fieldset is (dynamically or otherwise) added.
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.3.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 nested_partial, :f => f %>
6
- <%= f.hidden_field :_destroy %>
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] ? 'true' : 'false' %>
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 nested_partial, :f => nested_f %>
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>
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{nested_fields}
8
- s.version = "0.3.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-13}
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
- $(document).ready(function() {
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('nested_fields_ready');
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('div.nested_fields').hide();
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() == 'true' ? 'false' : 'true');
30
- $(this).closest('.nested_fieldset').find('.nested_one').toggle();
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
- function reposition(nested_fieldset, pos_fld) {
34
- $(nested_fieldset).find('> .nested_fields').each(function(i, nested_fields) {
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.3.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 00:00:00 -05:00
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: -167820414298998814
101
+ hash: -1830066020513997953
102
102
  segments:
103
103
  - 0
104
104
  version: "0"