nested_form 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/CHANGELOG.rdoc +12 -0
  2. data/README.md +165 -0
  3. data/Rakefile +7 -0
  4. data/lib/nested_form/builder_mixin.rb +13 -1
  5. data/spec/dummy/app/assets/javascripts/jquery_events_test.js +19 -0
  6. data/spec/dummy/app/assets/javascripts/jquery_nested_form.js +42 -10
  7. data/spec/dummy/app/assets/javascripts/prototype_events_test.js +20 -0
  8. data/spec/dummy/app/assets/javascripts/prototype_nested_form.js +37 -32
  9. data/spec/dummy/app/models/project.rb +2 -0
  10. data/spec/dummy/app/models/project_task.rb +3 -0
  11. data/spec/dummy/app/views/layouts/application.html.erb +8 -0
  12. data/spec/dummy/app/views/projects/new.html.erb +0 -6
  13. data/spec/dummy/app/views/projects/without_intermediate_inputs.html.erb +11 -0
  14. data/spec/dummy/config/routes.rb +3 -1
  15. data/spec/dummy/db/development.sqlite3 +0 -0
  16. data/spec/dummy/db/migrate/20120819164528_add_association_with_class_name.rb +12 -0
  17. data/spec/dummy/db/schema.rb +6 -1
  18. data/spec/dummy/db/test.sqlite3 +0 -0
  19. data/spec/dummy/log/development.log +91 -0
  20. data/spec/dummy/log/test.log +710 -25
  21. data/spec/dummy/tmp/cache/assets/C99/4D0/sprockets%2F5e30a6b911437f1428dc32c3ae182123 +0 -0
  22. data/spec/dummy/tmp/cache/assets/C99/7D0/sprockets%2F79513e6956e0ee8624976e041fd5636d +0 -0
  23. data/spec/dummy/tmp/cache/assets/CAA/C90/sprockets%2F1e6c8ee1258009385ccf5b84015424b3 +0 -0
  24. data/spec/dummy/tmp/cache/assets/CB2/CB0/sprockets%2F11cc8d161d71a716dd36f16849d90870 +0 -0
  25. data/spec/dummy/tmp/cache/assets/CB7/7F0/sprockets%2Fac97b043470f6fcc925c352f16956643 +0 -0
  26. data/spec/dummy/tmp/cache/assets/CDB/8A0/sprockets%2Faed2a2575c376263c26e93b56b57051d +0 -0
  27. data/spec/dummy/tmp/cache/assets/D1F/A10/sprockets%2F60317e62cb324bfd9987e8da9636fd06 +0 -0
  28. data/spec/dummy/tmp/cache/assets/D49/870/sprockets%2F90896142645585acc8baf56ad57e3afb +0 -0
  29. data/spec/dummy/tmp/cache/assets/D62/F00/sprockets%2F6ac03a007f26b1c18ed3d53498ad3eb8 +0 -0
  30. data/spec/dummy/tmp/cache/assets/D79/BC0/sprockets%2F85a1db977361cc5130fcefb4637ff67e +0 -0
  31. data/spec/dummy/tmp/cache/assets/D87/1F0/sprockets%2F61c9ceafb877fb740c67416ff6f782a9 +0 -0
  32. data/spec/dummy/tmp/cache/assets/DAD/4F0/sprockets%2F765acd1bf68dc90f7d3e61da78b1e659 +0 -0
  33. data/spec/dummy/tmp/cache/assets/E03/3F0/sprockets%2F82b37ae9eccec44c1ef44cfdd07d8534 +0 -0
  34. data/spec/dummy/tmp/cache/assets/E0A/CA0/sprockets%2F7fe72ac1c0db1a7e8e7f59cf25e8a39e +0 -0
  35. data/spec/dummy/tmp/cache/assets/E3A/A60/sprockets%2F7c72c96cfc66454caf5fc8ca0fedd4f3 +0 -0
  36. data/spec/dummy/tmp/cache/assets/E54/400/sprockets%2Fd0cbc16cc37efcf9dc41f242b5dbbf81 +0 -0
  37. data/spec/dummy/tmp/cache/assets/EB7/AB0/sprockets%2F801d29a5debdbfbfb4eef14d70d9bcdb +0 -0
  38. data/spec/dummy/tmp/cache/assets/F48/5E0/sprockets%2F26cd6ffcffbebbe2fd6cd1a8f0c2debc +0 -0
  39. data/spec/dummy/tmp/capybara/capybara-201208212241496415482929.html +31 -0
  40. data/spec/events_spec.rb +60 -0
  41. data/spec/form_spec.rb +9 -0
  42. data/spec/nested_form/builder_spec.rb +67 -19
  43. data/vendor/assets/javascripts/jquery_nested_form.js +42 -10
  44. data/vendor/assets/javascripts/prototype_nested_form.js +37 -32
  45. metadata +102 -72
  46. data/README.rdoc +0 -101
@@ -1,3 +1,15 @@
1
+ 0.2.3 (August 23, 2012)
2
+
3
+ * Fix selector for deeply nested forms (thanks groe)
4
+
5
+ * Fix association detection in #link_to remove (thanks nashbridges)
6
+
7
+ * Add nested:fieldRemoved:type event (thanks nashbridges)
8
+
9
+ * Add events for Prototype (thanks nashbridges)
10
+
11
+ * Element.up() is the proper Prototype counter part to jQuery's closest() (thanks clemens)
12
+
1
13
  0.2.2 (July 9, 2012)
2
14
 
3
15
  * Make deeply-nested form working in jruby and rubinius
@@ -0,0 +1,165 @@
1
+ # Nested Form
2
+
3
+ [<img src="https://secure.travis-ci.org/ryanb/nested_form.png?branch=master" alt="Build Status" />](http://travis-ci.org/ryanb/nested_form)
4
+
5
+ This is a Rails gem for conveniently manage multiple nested models in a single form. It does so in an unobtrusive way through jQuery or Prototype.
6
+
7
+ This gem only works with Rails 3. See the [rails2 branch](https://github.com/ryanb/nested_form/tree/rails2) for a plugin to work in Rails 2.
8
+
9
+ An example project showing how this works is available in the [complex-nested-forms/nested_form branch](https://github.com/ryanb/complex-form-examples/tree/nested_form).
10
+
11
+
12
+ ## Setup
13
+
14
+ Add it to your Gemfile then run `bundle` to install it.
15
+
16
+ ```ruby
17
+ gem "nested_form"
18
+ ```
19
+
20
+ And then add it to the Asset Pipeline in the application.js file:
21
+
22
+ ```
23
+ //= require jquery_nested_form
24
+ ```
25
+
26
+ ### Non Asset Pipeline Setup
27
+
28
+ If you do not use the asset pipeline, run this generator to create the JavaScript file.
29
+
30
+ ```
31
+ rails g nested_form:install
32
+ ```
33
+
34
+ You can then include the generated JavaScript in your layout.
35
+
36
+ ```erb
37
+ <%= javascript_include_tag :defaults, "nested_form" %>
38
+ ```
39
+
40
+ ## Usage
41
+
42
+ Imagine you have a `Project` model that `has_many :tasks`. To be able to use this gem, you'll need to add `accepts_nested_attributes_for :tasks` to your Project model. If you wish to allow the nested objects to be destroyed, then add the `:allow_destroy => true` option to that declaration. If you don't have the `accepts_nested_attributes_for :tasks` you'll get a Missing Block Error. See the [accepts_nested_attributes_for documentation](http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html#method-i-accepts_nested_attributes_for) for details on all available options.
43
+
44
+ This will create a `tasks_attributes=` method, so you may need to add it to the `attr_accessible` array (`attr_accessible :tasks_attributes`).
45
+
46
+ Then use the `nested_form_for` helper method to enable the nesting.
47
+
48
+ ```erb
49
+ <%= nested_form_for @project do |f| %>
50
+ ```
51
+
52
+ You will then be able to use `link_to_add` and `link_to_remove` helper methods on the form builder in combination with fields_for to dynamically add/remove nested records.
53
+
54
+ ```erb
55
+ <%= f.fields_for :tasks do |task_form| %>
56
+ <%= task_form.text_field :name %>
57
+ <%= task_form.link_to_remove "Remove this task" %>
58
+ <% end %>
59
+ <p><%= f.link_to_add "Add a task", :tasks %></p>
60
+ ```
61
+
62
+
63
+ ## SimpleForm and Formtastic Support
64
+
65
+ Use `simple_nested_form_for` or `semantic_nested_form_for` for SimpleForm and Formtastic support respectively.
66
+
67
+
68
+ ## Partials
69
+
70
+ It is often desirable to move the nested fields into a partial to keep things organized. If you don't supply a block to fields_for it will look for a partial and use that.
71
+
72
+ ```erb
73
+ <%= f.fields_for :tasks %>
74
+ ```
75
+
76
+ In this case it will look for a partial called "task_fields" and pass the form builder as an `f` variable to it.
77
+
78
+
79
+ ## JavaScript events
80
+
81
+ Sometimes you want to do some additional work after element was added or removed, but only
82
+ after DOM was _really_ modified. In this case simply listening for click events on
83
+ 'Add new'/'Remove' link won't reliably work, because your code and code that inserts/removes
84
+ nested field will run concurrently.
85
+
86
+ This problem can be solved, because after adding or removing the field a set of custom events
87
+ is triggered on this field. Using form example from above, if you click on the "Add a task" link,
88
+ `nested:fieldAdded` and `nested:fieldAdded:tasks` will be triggered, while
89
+ `nested:fieldRemoved` and `nested:fieldRemoved:tasks` will be triggered if you click
90
+ "Remove this task" then.
91
+
92
+ These events bubble up the DOM tree, going through `form` element, until they reach the `document`.
93
+ This allows you to listen for the event and trigger some action accordingly. Field element, upon
94
+ which action was made, is passed along with the `event` object. In jQuery you can access it
95
+ via `event.field`, in Prototype the same field will be in `event.memo.field`.
96
+
97
+ For example, you have a date input in a nested field and you want to use jQuery datepicker
98
+ for it. This is a bit tricky, because you have to activate datepicker after field was inserted.
99
+
100
+ ### jQuery
101
+
102
+ ```javascript
103
+ $(document).on('nested:fieldAdded', function(event){
104
+ // this field was just inserted into your form
105
+ var field = event.field;
106
+ // it's a jQuery object already! Now you can find date input
107
+ var dateField = field.find('.date');
108
+ // and activate datepicker on it
109
+ dateField.datepicker();
110
+ })
111
+ ```
112
+
113
+ ### Prototype
114
+
115
+ ```javascript
116
+ document.observe('nested:fieldAdded', function(event){
117
+ var field = event.memo.field;
118
+ // it's already extended by Prototype
119
+ var dateField = field.down('.date');
120
+ dateField.datepicker();
121
+ })
122
+ ```
123
+
124
+ Second type of event (i.e. `nested:fieldAdded:tasks`) is useful then you have more than one type
125
+ of nested fields on a form (i.e. tasks and milestones) and want to distinguish, which exactly
126
+ was added/deleted.
127
+
128
+ See also [how to limit max count of nested fields](https://github.com/ryanb/nested_form/wiki/How-to:-limit-max-count-of-nested-fields)
129
+
130
+ ## Enhanced jQuery JavaScript template
131
+
132
+ You can override default behavior of inserting new subforms into your form. For example:
133
+
134
+ ```javascript
135
+ window.nestedFormEvents.insertFields = function(content, assoc, link) {
136
+ return $(link).closest('form').find(assoc + '_fields').append($(content));
137
+ }
138
+ ```
139
+
140
+ ## Project Status
141
+
142
+ Unfortunately I have not had time to actively work on this project recently. If you find a critical issue where it does not work as documented please [ping me on Twitter](http://twitter.com/rbates) and I'll take a look.
143
+
144
+ ## Contributing
145
+
146
+ If you have any issues with Nested Form not addressed above or in the [example project](http://github.com/ryanb/complex-form-examples/tree/nested_form), please add an [issue on GitHub](http://github.com/ryanb/nested_form/issues) or [fork the project](http://help.github.com/fork-a-repo) and send a [pull request](http://help.github.com/send-pull-requests). To run the specs:
147
+
148
+ ```
149
+ bundle install
150
+ bundle exec rake spec:install
151
+ bundle exec rake db:migrate
152
+ bundle exec rake spec:all
153
+ ```
154
+
155
+ See available rake tasks using `bundle exec rake -T`.
156
+
157
+ ## Special Thanks
158
+
159
+ This gem was originally based on the solution by Tim Riley in his [complex-form-examples fork](https://github.com/timriley/complex-form-examples/tree/unobtrusive-jquery-deep-fix2).
160
+
161
+ Thank you Andrew Manshin for the Rails 3 transition, [Andrea Singh](https://github.com/madebydna) for converting to a gem and [Peter Giacomo Lombardo](https://github.com/pglombardo) for Prototype support.
162
+
163
+ Andrea also wrote a great [blog post](http://blog.madebydna.com/all/code/2010/10/07/dynamic-nested-froms-with-the-nested-form-gem.html) on the internal workings of this gem.
164
+
165
+ Thanks [Pavel Forkert](https://github.com/fxposter) for the SimpleForm and Formtastic support.
data/Rakefile CHANGED
@@ -14,26 +14,33 @@ end
14
14
  task :default => :spec
15
15
 
16
16
  namespace :db do
17
+ desc 'Prepare sqlite database'
17
18
  task :migrate do
18
19
  system 'cd spec/dummy && rake db:migrate RAILS_ENV=test && rake db:migrate RAILS_ENV=development'
19
20
  end
20
21
  end
21
22
 
22
23
  namespace :spec do
24
+ desc 'Install gems from additional gemfiles'
23
25
  task :install do
24
26
  system 'bundle install'
27
+ ENV.delete('GEM_HOME')
25
28
  ENV['BUNDLE_GEMFILE'] = File.expand_path('../gemfiles/Gemfile.rails3_1', __FILE__)
26
29
  system 'bundle install'
27
30
  ENV['BUNDLE_GEMFILE'] = File.expand_path('../gemfiles/Gemfile.rails3_0', __FILE__)
28
31
  system 'bundle install'
29
32
  end
30
33
 
34
+ desc 'Run tests with Rails 3.1.x'
31
35
  task :rails3_1 do
36
+ ENV.delete('GEM_HOME')
32
37
  ENV['BUNDLE_GEMFILE'] = File.expand_path('../gemfiles/Gemfile.rails3_1', __FILE__)
33
38
  Rake::Task["spec"].execute
34
39
  end
35
40
 
41
+ desc 'Run tests with Rails 3.0.x'
36
42
  task :rails3_0 do
43
+ ENV.delete('GEM_HOME')
37
44
  ENV['BUNDLE_GEMFILE'] = File.expand_path('../gemfiles/Gemfile.rails3_0', __FILE__)
38
45
  Rake::Task["spec"].execute
39
46
  end
@@ -14,13 +14,19 @@ module NestedForm
14
14
  def link_to_add(*args, &block)
15
15
  options = args.extract_options!.symbolize_keys
16
16
  association = args.pop
17
+
18
+ unless (reflection = object.class.reflect_on_association(association))
19
+ raise ArgumentError, "Failed to find #{object.class.name} association by name \"#{association}\""
20
+ end
21
+ model_object = reflection.klass.new
22
+
17
23
  options[:class] = [options[:class], "add_nested_fields"].compact.join(" ")
18
24
  options["data-association"] = association
19
25
  args << (options.delete(:href) || "javascript:void(0)")
20
26
  args << options
27
+
21
28
  @fields ||= {}
22
29
  @template.after_nested_form(association) do
23
- model_object = object.class.reflect_on_association(association).klass.new
24
30
  blueprint = fields_for(association, model_object, :child_index => "new_#{association}", &@fields[association])
25
31
  blueprint_options = {:id => "#{association}_fields_blueprint", :style => 'display: none'}
26
32
  @template.content_tag(:div, blueprint, blueprint_options)
@@ -42,6 +48,12 @@ module NestedForm
42
48
  def link_to_remove(*args, &block)
43
49
  options = args.extract_options!.symbolize_keys
44
50
  options[:class] = [options[:class], "remove_nested_fields"].compact.join(" ")
51
+
52
+ # Extracting "milestones" from "...[milestones_attributes][...]"
53
+ md = object_name.to_s.match /(\w+)_attributes\]\[[\w\d]+\]$/
54
+ association = md && md[1]
55
+ options["data-association"] = association
56
+
45
57
  args << (options.delete(:href) || "javascript:void(0)")
46
58
  args << options
47
59
  (hidden_field(:_destroy) << @template.link_to(*args, &block)).html_safe
@@ -0,0 +1,19 @@
1
+ $(function() {
2
+ var log = function(text) {
3
+ $('<p/>', {text: text}).appendTo('#console');
4
+ };
5
+
6
+ ['Added', 'Removed'].forEach(function(action) {
7
+ $(document).on('nested:field' + action, function(e) {
8
+ log(action + ' some field')
9
+ });
10
+
11
+ $(document).on('nested:field' + action + ':tasks', function(e) {
12
+ log(action + ' task field')
13
+ });
14
+
15
+ $(document).on('nested:field' + action + ':milestones', function(e) {
16
+ log(action + ' milestone field')
17
+ });
18
+ });
19
+ });
@@ -13,7 +13,7 @@ jQuery(function($) {
13
13
 
14
14
  // Make the context correct by replacing new_<parents> with the generated ID
15
15
  // of each of the parent objects
16
- var context = ($(link).closest('.fields').find('input:first').attr('name') || '').replace(new RegExp('\[[a-z]+\]$'), '');
16
+ var context = ($(link).closest('.fields').closestChild('input, textarea').eq(0).attr('name') || '').replace(new RegExp('\[[a-z]+\]$'), '');
17
17
 
18
18
  // context will be something like this for a brand new form:
19
19
  // project[tasks_attributes][new_1255929127459][assignments_attributes][new_1255929128105]
@@ -42,7 +42,8 @@ jQuery(function($) {
42
42
  content = content.replace(regexp, "new_" + new_id);
43
43
 
44
44
  var field = this.insertFields(content, assoc, link);
45
- $(link).closest("form")
45
+ // bubble up event upto document (through form)
46
+ field
46
47
  .trigger({ type: 'nested:fieldAdded', field: field })
47
48
  .trigger({ type: 'nested:fieldAdded:' + assoc, field: field });
48
49
  return false;
@@ -51,16 +52,18 @@ jQuery(function($) {
51
52
  return $(content).insertBefore(link);
52
53
  },
53
54
  removeFields: function(e) {
54
- var link = e.currentTarget;
55
- var hiddenField = $(link).prev('input[type=hidden]');
55
+ var $link = $(e.currentTarget),
56
+ assoc = $link.data('association'); // Name of child to be removed
57
+
58
+ var hiddenField = $link.prev('input[type=hidden]');
56
59
  hiddenField.val('1');
57
- // if (hiddenField) {
58
- // $(link).v
59
- // hiddenField.value = '1';
60
- // }
61
- var field = $(link).closest('.fields');
60
+
61
+ var field = $link.closest('.fields');
62
62
  field.hide();
63
- $(link).closest("form").trigger({ type: 'nested:fieldRemoved', field: field });
63
+
64
+ field
65
+ .trigger({ type: 'nested:fieldRemoved', field: field })
66
+ .trigger({ type: 'nested:fieldRemoved:' + assoc, field: field });
64
67
  return false;
65
68
  }
66
69
  };
@@ -69,3 +72,32 @@ jQuery(function($) {
69
72
  $('form a.add_nested_fields').live('click', nestedFormEvents.addFields);
70
73
  $('form a.remove_nested_fields').live('click', nestedFormEvents.removeFields);
71
74
  });
75
+ // http://plugins.jquery.com/project/closestChild
76
+ /*
77
+ * Copyright 2011, Tobias Lindig
78
+ *
79
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
80
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
81
+ *
82
+ */
83
+ (function($) {
84
+ $.fn.closestChild = function(selector) {
85
+ // breadth first search for the first matched node
86
+ if (selector && selector != '') {
87
+ var queue = [];
88
+ queue.push(this);
89
+ while(queue.length > 0) {
90
+ var node = queue.shift();
91
+ var children = node.children();
92
+ for(var i = 0; i < children.length; ++i) {
93
+ var child = $(children[i]);
94
+ if (child.is(selector)) {
95
+ return child; //well, we found one
96
+ }
97
+ queue.push(child);
98
+ }
99
+ }
100
+ }
101
+ return $();//nothing found
102
+ };
103
+ })(jQuery);
@@ -0,0 +1,20 @@
1
+ document.observe('dom:loaded', function() {
2
+ var log = function(text) {
3
+ var p = new Element('p').update(text);
4
+ $('console').insert(p);
5
+ };
6
+
7
+ ['Added', 'Removed'].forEach(function(action) {
8
+ document.observe('nested:field' + action, function(e) {
9
+ log(action + ' some field')
10
+ });
11
+
12
+ document.observe('nested:field' + action + ':tasks', function(e) {
13
+ log(action + ' task field')
14
+ });
15
+
16
+ document.observe('nested:field' + action + ':milestones', function(e) {
17
+ log(action + ' milestone field')
18
+ });
19
+ });
20
+ });
@@ -1,22 +1,22 @@
1
1
  document.observe('click', function(e, el) {
2
- if (el = e.findElement('form a.add_nested_fields')) {
3
- // Setup
4
- var assoc = el.readAttribute('data-association'); // Name of child
5
- var content = $(assoc + '_fields_blueprint').innerHTML; // Fields template
2
+ if (el = e.findElement('form a.add_nested_fields')) {
3
+ // Setup
4
+ var assoc = el.readAttribute('data-association'); // Name of child
5
+ var content = $(assoc + '_fields_blueprint').innerHTML; // Fields template
6
6
 
7
- // Make the context correct by replacing new_<parents> with the generated ID
8
- // of each of the parent objects
9
- var context = (el.getOffsetParent('.fields').firstDescendant().readAttribute('name') || '').replace(new RegExp('\[[a-z]+\]$'), '');
7
+ // Make the context correct by replacing new_<parents> with the generated ID
8
+ // of each of the parent objects
9
+ var context = (el.getOffsetParent('.fields').firstDescendant().readAttribute('name') || '').replace(new RegExp('\[[a-z]+\]$'), '');
10
10
 
11
- // context will be something like this for a brand new form:
12
- // project[tasks_attributes][new_1255929127459][assignments_attributes][new_1255929128105]
13
- // or for an edit form:
14
- // project[tasks_attributes][0][assignments_attributes][1]
15
- if(context) {
16
- var parent_names = context.match(/[a-z_]+_attributes/g) || [];
17
- var parent_ids = context.match(/(new_)?[0-9]+/g) || [];
11
+ // context will be something like this for a brand new form:
12
+ // project[tasks_attributes][new_1255929127459][assignments_attributes][new_1255929128105]
13
+ // or for an edit form:
14
+ // project[tasks_attributes][0][assignments_attributes][1]
15
+ if(context) {
16
+ var parent_names = context.match(/[a-z_]+_attributes/g) || [];
17
+ var parent_ids = context.match(/(new_)?[0-9]+/g) || [];
18
18
 
19
- for(i = 0; i < parent_names.length; i++) {
19
+ for(i = 0; i < parent_names.length; i++) {
20
20
  if(parent_ids[i]) {
21
21
  content = content.replace(
22
22
  new RegExp('(_' + parent_names[i] + ')_.+?_', 'g'),
@@ -26,26 +26,31 @@ document.observe('click', function(e, el) {
26
26
  new RegExp('(\\[' + parent_names[i] + '\\])\\[.+?\\]', 'g'),
27
27
  '$1[' + parent_ids[i] + ']');
28
28
  }
29
- }
30
- }
29
+ }
30
+ }
31
31
 
32
- // Make a unique ID for the new child
33
- var regexp = new RegExp('new_' + assoc, 'g');
34
- var new_id = new Date().getTime();
35
- content = content.replace(regexp, "new_" + new_id);
32
+ // Make a unique ID for the new child
33
+ var regexp = new RegExp('new_' + assoc, 'g');
34
+ var new_id = new Date().getTime();
35
+ content = content.replace(regexp, "new_" + new_id);
36
36
 
37
- el.insert({ before: content });
38
- return false;
39
- }
37
+ var field = el.insert({ before: content });
38
+ field.fire('nested:fieldAdded', {field: field});
39
+ field.fire('nested:fieldAdded:' + assoc, {field: field});
40
+ return false;
41
+ }
40
42
  });
41
43
 
42
44
  document.observe('click', function(e, el) {
43
- if (el = e.findElement('form a.remove_nested_fields')) {
44
- var hidden_field = el.previous(0);
45
- if(hidden_field) {
46
- hidden_field.value = '1';
47
- }
48
- el.ancestors()[0].hide();
49
- return false;
50
- }
45
+ if (el = e.findElement('form a.remove_nested_fields')) {
46
+ var hidden_field = el.previous(0),
47
+ assoc = el.readAttribute('data-association'); // Name of child to be removed
48
+ if(hidden_field) {
49
+ hidden_field.value = '1';
50
+ }
51
+ var field = el.up('.fields').hide();
52
+ field.fire('nested:fieldRemoved', {field: field});
53
+ field.fire('nested:fieldRemoved:' + assoc, {field: field});
54
+ return false;
55
+ }
51
56
  });