├── .gitignore
├── Gruntfile.js
├── LICENSE.txt
├── README.md
├── changelog.md
├── example.html
├── jquery.multifield.js
├── jquery.multifield.min.js
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function (grunt) {
2 | grunt.initConfig({
3 | pkg: grunt.file.readJSON('package.json'),
4 |
5 | jshint: {
6 | options: {
7 | curly: true,
8 | eqeqeq: true,
9 | immed: true,
10 | latedef: true,
11 | newcap: true,
12 | noarg: true,
13 | sub: true,
14 | undef: true,
15 | eqnull: true,
16 | browser: true,
17 | globals: {
18 | jQuery: true,
19 | $: true,
20 | console: true
21 | }
22 | },
23 | '<%= pkg.name %>': {
24 | src: [ 'src/js/**/*.js' ]
25 | }
26 | },
27 |
28 | uglify: {
29 | options: {
30 | stripBanners: true,
31 | banner: '/* <%= pkg.name %> - v<%= pkg.version %> - <%= pkg.homepage %> */\n'
32 | },
33 |
34 | build: {
35 | src: 'jquery.multifield.js',
36 | dest: 'jquery.multifield.min.js'
37 | }
38 | },
39 |
40 |
41 | });
42 |
43 |
44 | grunt.loadNpmTasks('grunt-contrib-jshint');
45 | grunt.loadNpmTasks('grunt-contrib-uglify');
46 |
47 |
48 | grunt.registerTask('default', ['jshint', 'uglify']);
49 | };
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Max Kostinevich
4 | https://maxkostinevich.com
5 |
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in
15 | all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # jQuery Multifield Plugin
2 |
3 | A jQuery plugin which allows you to create dynamic field groups.
4 |
5 | ## USAGE
6 |
7 | ```
14 | ```
15 |
16 | ## DEMO
17 |
18 | 
19 |
20 | Demo is available [here](http://maxkostinevich.github.io/jquery-multifield/): http://maxkostinevich.github.io/jquery-multifield/
21 |
22 | ## CHANGELOG
23 |
24 | ```
25 | v2.0.0 - September 21, 2016
26 | ** Updates **
27 | - Localization strings now passed through the 'locale' option as an object
28 | ```
29 |
30 | ```
31 | v1.0.0 - June 30,2015
32 | ** Initial Release **
33 | ```
34 |
35 |
36 | ## [MIT License](https://opensource.org/licenses/MIT)
37 | (c) 2015 - 2016 [Max Kostinevich](https://maxkostinevich.com) - All rights reserved.
38 |
39 |
--------------------------------------------------------------------------------
/changelog.md:
--------------------------------------------------------------------------------
1 | CHANGELOG
2 | -----
3 |
4 | 1.0.0
5 | ---
6 | - Initial release
--------------------------------------------------------------------------------
/example.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | jQuery Multifield Example
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
jQuery Multifield Plugin
34 |
A jQuery plugin which allows you to create dynamic field groups.
35 |
GitHub Page
36 |
37 | Star
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
Plugin Init
47 |
48 | <script>
49 | $('#wrapper').multifield({
50 | section: '.section',
51 | btnAdd:'.btnAdd',
52 | btnRemove:'.btnRemove'
53 | });
54 | </script>
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
Plugin Options
64 |
65 |
66 |
67 | Option |
68 | Type |
69 | Default |
70 | Description |
71 |
72 |
73 |
74 |
75 | section |
76 | string |
77 | null |
78 | REQUIRED Selector of the section which is located inside of the parent wrapper |
79 |
80 |
81 | btnAdd |
82 | string |
83 | null |
84 | REQUIRED Selector of the "Add section" button - can be located everywhere on the page |
85 |
86 |
87 | btnRemove |
88 | string |
89 | null |
90 | REQUIRED Selector of the "Remove section" button - should be located INSIDE of the "section" |
91 |
92 |
93 | max |
94 | integer |
95 | 0 |
96 | Maximum section |
97 |
98 |
99 | locale |
100 | string |
101 | 'default' |
102 | Language to use, default is english |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
Basic usage #1 (HTML5 data-attribute options) SOURCE
114 |
115 |
116 |
117 | <div id="example-1" class="content" data-mfield-options='{"section": ".group","btnAdd":"#btnAdd-1","btnRemove":".btnRemove"}'>
118 | <div class="row">
119 | <div class="col-md-12"><button type="button" id="btnAdd-1" class="btn btn-primary">Add section</button></div>
120 | </div>
121 | <div class="row group">
122 | <div class="col-md-2">
123 | <input class="form-control" type="text">
124 | </div>
125 | <div class="col-md-2">
126 | <input class="form-control" type="text">
127 | </div>
128 | <div class="col-md-4">
129 | <textarea></textarea>
130 | </div>
131 | <div class="col-md-3">
132 | <button type="button" class="btn btn-danger btnRemove">Remove</button>
133 | </div>
134 | </div>
135 | </div>
136 |
137 |
138 | <script>
139 | $('#example-1').multifield();
140 | </script>
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
Basic usage #2 (JavaScript options) SOURCE
171 |
172 |
173 | <div id="example-2" class="content">
174 | <div class="row">
175 | <div class="col-md-12"><button type="button" id="btnAdd-2" class="btn btn-primary">Add section</button></div>
176 | </div>
177 | <div class="row group">
178 | <div class="col-md-2">
179 | <input class="form-control" type="text">
180 | </div>
181 | <div class="col-md-2">
182 | <input class="form-control" type="text">
183 | </div>
184 | <div class="col-md-4">
185 | <textarea></textarea>
186 | </div>
187 | <div class="col-md-3">
188 | <button type="button" class="btn btn-danger btnRemove">Remove</button>
189 | </div>
190 | </div>
191 | </div>
192 |
193 |
194 | <script>
195 | $('#example-2').multifield({
196 | section: '.group',
197 | btnAdd:'#btnAdd-2',
198 | btnRemove:'.btnRemove'
199 | });
200 | </script>
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
Example #3 (The maximum sections count) SOURCE
232 |
You can set maximum sections count via 'max' option.
233 |
234 |
235 | <div id="example-3" class="content">
236 | <div class="row">
237 | <div class="col-md-12"><button type="button" id="btnAdd-3" class="btn btn-primary">Add section</button></div>
238 | </div>
239 | <div class="row group">
240 | <div class="col-md-2">
241 | <input class="form-control" type="text">
242 | </div>
243 | <div class="col-md-2">
244 | <input class="form-control" type="text">
245 | </div>
246 | <div class="col-md-4">
247 | <textarea></textarea>
248 | </div>
249 | <div class="col-md-3">
250 | <button type="button" class="btn btn-danger btnRemove">Remove</button>
251 | </div>
252 | </div>
253 | </div>
254 |
255 |
256 | <script>
257 | $('#example-3').multifield({
258 | section: '.group',
259 | btnAdd:'#btnAdd-3',
260 | btnRemove:'.btnRemove',
261 | max: 3
262 | });
263 | </script>
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
Example #4 (Localization) SOURCE
294 |
You can translate confirmation message which appears on section remove.
295 |
To do so just pass an object with translated strings through the 'locale' option.
296 |
297 |
298 | <div id="example-4" class="content">
299 | <div class="row">
300 | <div class="col-md-12"><button type="button" id="btnAdd-4" class="btn btn-primary">Добавить</button></div>
301 | </div>
302 | <div class="row group">
303 | <div class="col-md-2">
304 | <input class="form-control" type="text">
305 | </div>
306 | <div class="col-md-2">
307 | <input class="form-control" type="text">
308 | </div>
309 | <div class="col-md-4">
310 | <textarea></textarea>
311 | </div>
312 | <div class="col-md-3">
313 | <button type="button" class="btn btn-danger btnRemove">Удалить</button>
314 | </div>
315 | </div>
316 | </div>
317 |
318 |
319 | <script>
320 | $('#example-4').multifield({
321 | section: '.group',
322 | btnAdd:'#btnAdd-4',
323 | btnRemove:'.btnRemove',
324 | locale:{
325 | "multiField": {
326 | "messages": {
327 | "removeConfirmation": "Вы уверены, что вы хотите удалить этот элемент?"
328 | }
329 | }
330 | }
331 | });
332 | </script>
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
Example #5 (Advanced) SOURCE
364 |
365 | To use radio buttons you should add numeric value to their names, for example: name="group[0]"
366 |
367 |
Add "reset-image-src" class to image to reset image src
368 |
369 |
370 | <div id="example-5" class="content">
371 | <div class="row">
372 | <div class="col-md-12"><button type="button" id="btnAdd-5" class="btn btn-primary">Add section</button></div>
373 | </div>
374 | <div class="row group">
375 | <div class="col-md-2">
376 | <select name="select_example[]">
377 | <option value="1">Option 1</option>
378 | <option value="2">Option 2</option>
379 | <option value="3">Option 3</option>
380 | </select>
381 | </div>
382 | <div class="col-md-2">
383 | <input type="radio" name="radio_example[0]" value="1"> Option 1 <br>
384 | <input type="radio" name="radio_example[0]" value="2"> Option 2 <br>
385 | <input type="radio" name="radio_example[0]" value="3"> Option 3 <br>
386 | </div>
387 | <div class="col-md-3">
388 | <p>Image src will not be cleared</p>
389 | <img class="media-object" alt="64x64" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIHZpZXdCb3g9IjAgMCA2NCA2NCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+PCEtLQpTb3VyY2UgVVJMOiBob2xkZXIuanMvNjR4NjQKQ3JlYXRlZCB3aXRoIEhvbGRlci5qcyAyLjYuMC4KTGVhcm4gbW9yZSBhdCBodHRwOi8vaG9sZGVyanMuY29tCihjKSAyMDEyLTIwMTUgSXZhbiBNYWxvcGluc2t5IC0gaHR0cDovL2ltc2t5LmNvCi0tPjxkZWZzPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+PCFbQ0RBVEFbI2hvbGRlcl8xNGU0MzRkMDhhOCB0ZXh0IHsgZmlsbDojQUFBQUFBO2ZvbnQtd2VpZ2h0OmJvbGQ7Zm9udC1mYW1pbHk6QXJpYWwsIEhlbHZldGljYSwgT3BlbiBTYW5zLCBzYW5zLXNlcmlmLCBtb25vc3BhY2U7Zm9udC1zaXplOjEwcHQgfSBdXT48L3N0eWxlPjwvZGVmcz48ZyBpZD0iaG9sZGVyXzE0ZTQzNGQwOGE4Ij48cmVjdCB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIGZpbGw9IiNFRUVFRUUiLz48Zz48dGV4dCB4PSIxNC41IiB5PSIzNi41Ij42NHg2NDwvdGV4dD48L2c+PC9nPjwvc3ZnPg==" style="width: 64px; height: 64px;">
390 | </div>
391 | <div class="col-md-2">
392 | <p>Image src will be cleared</p>
393 | <img class="media-object reset-image-src" alt="Image" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIHZpZXdCb3g9IjAgMCA2NCA2NCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+PCEtLQpTb3VyY2UgVVJMOiBob2xkZXIuanMvNjR4NjQKQ3JlYXRlZCB3aXRoIEhvbGRlci5qcyAyLjYuMC4KTGVhcm4gbW9yZSBhdCBodHRwOi8vaG9sZGVyanMuY29tCihjKSAyMDEyLTIwMTUgSXZhbiBNYWxvcGluc2t5IC0gaHR0cDovL2ltc2t5LmNvCi0tPjxkZWZzPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+PCFbQ0RBVEFbI2hvbGRlcl8xNGU0MzRkMDhhOCB0ZXh0IHsgZmlsbDojQUFBQUFBO2ZvbnQtd2VpZ2h0OmJvbGQ7Zm9udC1mYW1pbHk6QXJpYWwsIEhlbHZldGljYSwgT3BlbiBTYW5zLCBzYW5zLXNlcmlmLCBtb25vc3BhY2U7Zm9udC1zaXplOjEwcHQgfSBdXT48L3N0eWxlPjwvZGVmcz48ZyBpZD0iaG9sZGVyXzE0ZTQzNGQwOGE4Ij48cmVjdCB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIGZpbGw9IiNFRUVFRUUiLz48Zz48dGV4dCB4PSIxNC41IiB5PSIzNi41Ij42NHg2NDwvdGV4dD48L2c+PC9nPjwvc3ZnPg==" style="width: 64px; height: 64px;">
394 | </div>
395 | <div class="col-md-2">
396 | <button type="button" class="btn btn-danger btnRemove">Remove</button>
397 | </div>
398 | </div>
399 | </div>
400 |
401 |
402 | <script>
403 | $('#example-5').multifield({
404 | section: '.group',
405 | btnAdd:'#btnAdd-5',
406 | btnRemove:'.btnRemove',
407 | });
408 | </script>
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
419 |
420 |
421 |
426 |
427 |
428 | Option 1
429 | Option 2
430 | Option 3
431 |
432 |
433 |
Image src will not be cleared
434 |

435 |
436 |
437 |
Image src will be cleared
438 |

439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
Example #6 (Handling data with PHP) SOURCE
450 |
451 |
452 | <form method="post">
453 | <div id="example-6" class="content">
454 | <div class="row">
455 | <div class="col-md-12"><button type="button" id="btnAdd-6" class="btn btn-primary">Add Employee</button></div>
456 | </div>
457 | <div class="row group">
458 | <div class="col-md-2">
459 | <div class="form-group">
460 | <label>Name<input class="form-control" class="form-control" type="text" name="user_name[]"></label>
461 | </div>
462 | </div>
463 | <div class="col-md-2">
464 | <label>Gender
465 | <select name="user_gender[]" class="form-control">
466 | <option value="">Please select..</option>
467 | <option value="male">Male</option>
468 | <option value="female">Female</option>
469 | </select>
470 | </label>
471 | </div>
472 | <div class="col-md-4">
473 | <div class="col-md-2">
474 | <div class="radio">
475 | <label><input type="radio" name="user_role[0]" value="manager"> Manager </label>
476 | </div>
477 | <div class="radio">
478 | <label><input type="radio" name="user_role[0]" value="editor"> Editor </label>
479 | </div>
480 | <div class="radio">
481 | <label class="checkbox-inline"><input type="radio" name="user_role[0]" value="writer"> Writer </label>
482 | </div>
483 | </div>
484 | </div>
485 | <div class="col-md-3">
486 | <button type="button" class="btn btn-danger btnRemove">Remove</button>
487 | </div>
488 | </div>
489 | </div>
490 | </form>
491 |
492 |
493 | <script>
494 | $('#example-6').multifield({
495 | section: '.group',
496 | btnAdd:'#btnAdd-6',
497 | btnRemove:'.btnRemove',
498 | });
499 | </script>
500 |
501 |
502 | <?php var_dump($_POST); ?>
503 |
504 | OUTPUT :
505 |
506 | 'user_name' =>
507 | array (size=5)
508 | 0 => string 'John Doe' (length=8)
509 | 1 => string 'Alice Smith' (length=11)
510 | 2 => string 'Jason Louis' (length=11)
511 | 3 => string 'Bob Freeman' (length=11)
512 | 4 => string 'Jane Watkins' (length=12)
513 | 'user_gender' =>
514 | array (size=5)
515 | 0 => string 'male' (length=4)
516 | 1 => string 'female' (length=6)
517 | 2 => string 'male' (length=4)
518 | 3 => string 'male' (length=4)
519 | 4 => string 'female' (length=6)
520 | 'user_role' =>
521 | array (size=5)
522 | 0 => string 'manager' (length=7)
523 | 1 => string 'editor' (length=6)
524 | 2 => string 'writer' (length=6)
525 | 3 => string 'writer' (length=6)
526 | 4 => string 'writer' (length=6)
527 |
528 | // Get information about the first record
529 | $_POST['user_name'][0]; // John Doe
530 | $_POST['user_gender'][0]; // male
531 | $_POST['user_role'][0]; // manager
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
557 |
558 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
637 |
638 |
639 |
640 |
641 |
--------------------------------------------------------------------------------
/jquery.multifield.js:
--------------------------------------------------------------------------------
1 | /**
2 | * jQuery Multifield plugin
3 | *
4 | * https://github.com/maxkostinevich/jquery-multifield
5 | */
6 |
7 |
8 | // the semi-colon before function invocation is a safety net against concatenated
9 | // scripts and/or other plugins which may not be closed properly.
10 | ;(function ( $, window, document, undefined ) {
11 |
12 | /*
13 | * Plugin Options
14 | * section (string) - selector of the section which is located inside of the parent wrapper
15 | * max (int) - Maximum sections
16 | * btnAdd (string) - selector of the "Add section" button - can be located everywhere on the page
17 | * btnRemove (string) - selector of the "Remove section" button - should be located INSIDE of the "section"
18 | * locale (string) - language to use, default is english
19 | */
20 |
21 | // our plugin constructor
22 | var multiField = function( elem, options ){
23 | this.elem = elem;
24 | this.$elem = $(elem);
25 | this.options = options;
26 | // Localization
27 | this.localize_i18n={
28 | "multiField": {
29 | "messages": {
30 | "removeConfirmation": "Are you sure you want to remove this section?"
31 | }
32 | }
33 | };
34 |
35 | // This next line takes advantage of HTML5 data attributes
36 | // to support customization of the plugin on a per-element
37 | // basis. For example,
38 | //
39 | this.metadata = this.$elem.data( 'mfield-options' );
40 | };
41 |
42 | // the plugin prototype
43 | multiField.prototype = {
44 |
45 | defaults: {
46 | max: 0,
47 | locale: 'default'
48 | },
49 |
50 |
51 | init: function() {
52 | var $this = this; //Plugin object
53 | // Introduce defaults that can be extended either
54 | // globally or using an object literal.
55 | this.config = $.extend({}, this.defaults, this.options,
56 | this.metadata);
57 |
58 | // Load localization object
59 | if(this.config.locale !== 'default'){
60 | $this.localize_i18n = this.config.locale;
61 | }
62 |
63 | // Hide 'Remove' buttons if only one section exists
64 | if(this.getSectionsCount()<2) {
65 | $(this.config.btnRemove, this.$elem).hide();
66 | }
67 |
68 | // Add section
69 | this.$elem.on('click',this.config.btnAdd,function(e){
70 | e.preventDefault();
71 | $this.cloneSection();
72 | });
73 |
74 | // Remove section
75 | this.$elem.on('click',this.config.btnRemove,function(e){
76 | e.preventDefault();
77 | var currentSection=$(e.target.closest($this.config.section));
78 | $this.removeSection(currentSection);
79 | });
80 |
81 | return this;
82 | },
83 |
84 |
85 | /*
86 | * Add new section
87 | */
88 | cloneSection : function() {
89 | // Allow to add only allowed max count of sections
90 | if((this.config.max!==0)&&(this.getSectionsCount()+1)>this.config.max){
91 | return false;
92 | }
93 |
94 | // Clone last section
95 | var newChild = $(this.config.section, this.$elem).last().clone().attr('style', '').attr('id', '').fadeIn('fast');
96 |
97 |
98 | // Clear input values
99 | $('input[type!="radio"],textarea', newChild).each(function () {
100 | $(this).val('');
101 | });
102 |
103 | // Fix radio buttons: update name [i] to [i+1]
104 | newChild.find('input[type="radio"]').each(function(){var name=$(this).attr('name');$(this).attr('name',name.replace(/([0-9]+)/g,1*(name.match(/([0-9]+)/g))+1));});
105 | // Reset radio button selection
106 | $('input[type=radio]',newChild).attr('checked', false);
107 |
108 | // Clear images src with reset-image-src class
109 | $('img.reset-image-src', newChild).each(function () {
110 | $(this).attr('src', '');
111 | });
112 |
113 | // Append new section
114 | this.$elem.append(newChild);
115 |
116 | // Show 'remove' button
117 | $(this.config.btnRemove, this.$elem).show();
118 | },
119 |
120 | /*
121 | * Remove existing section
122 | */
123 | removeSection : function(section){
124 | if (confirm(this.localize_i18n.multiField.messages.removeConfirmation)){
125 | var sectionsCount = this.getSectionsCount();
126 |
127 | if(sectionsCount<=2){
128 | $(this.config.btnRemove,this.$elem).hide();
129 | }
130 | section.slideUp('fast', function () {$(this).detach();});
131 | }
132 | },
133 |
134 | /*
135 | * Get sections count
136 | */
137 | getSectionsCount: function(){
138 | return this.$elem.children(this.config.section).length;
139 | }
140 |
141 | };
142 |
143 | multiField.defaults = multiField.prototype.defaults;
144 |
145 | $.fn.multifield = function(options) {
146 | return this.each(function() {
147 | new multiField(this, options).init();
148 | });
149 | };
150 |
151 |
152 |
153 | })( jQuery, window, document );
154 |
--------------------------------------------------------------------------------
/jquery.multifield.min.js:
--------------------------------------------------------------------------------
1 | /* jquery-multifield - v2.0.0 - https://github.com/maxkostinevich/jquery-multifield */
2 | !function(a,b,c,d){var e=function(b,c){this.elem=b,this.$elem=a(b),this.options=c,this.localize_i18n={multiField:{messages:{removeConfirmation:"Are you sure you want to remove this section?"}}},this.metadata=this.$elem.data("mfield-options")};e.prototype={defaults:{max:0,locale:"default"},init:function(){var b=this;return this.config=a.extend({},this.defaults,this.options,this.metadata),"default"!==this.config.locale&&(b.localize_i18n=this.config.locale),this.getSectionsCount()<2&&a(this.config.btnRemove,this.$elem).hide(),this.$elem.on("click",this.config.btnAdd,function(a){a.preventDefault(),b.cloneSection()}),this.$elem.on("click",this.config.btnRemove,function(c){c.preventDefault();var d=a(c.target.closest(b.config.section));b.removeSection(d)}),this},cloneSection:function(){if(0!==this.config.max&&this.getSectionsCount()+1>this.config.max)return!1;var b=a(this.config.section,this.$elem).last().clone().attr("style","").attr("id","").fadeIn("fast");a('input[type!="radio"],textarea',b).each(function(){a(this).val("")}),b.find('input[type="radio"]').each(function(){var b=a(this).attr("name");a(this).attr("name",b.replace(/([0-9]+)/g,1*b.match(/([0-9]+)/g)+1))}),a("input[type=radio]",b).attr("checked",!1),a("img.reset-image-src",b).each(function(){a(this).attr("src","")}),this.$elem.append(b),a(this.config.btnRemove,this.$elem).show()},removeSection:function(b){if(confirm(this.localize_i18n.multiField.messages.removeConfirmation)){var c=this.getSectionsCount();c<=2&&a(this.config.btnRemove,this.$elem).hide(),b.slideUp("fast",function(){a(this).detach()})}},getSectionsCount:function(){return this.$elem.children(this.config.section).length}},e.defaults=e.prototype.defaults,a.fn.multifield=function(a){return this.each(function(){new e(this,a).init()})}}(jQuery,window,document);
3 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-multifield",
3 | "version": "2.0.0",
4 | "author": {
5 | "name": "Max Kostinevich",
6 | "url": "https://maxkostinevich.com"
7 | },
8 | "description": "A jQuery plugin which allows you to create dynamic field groups.",
9 | "licenses": [
10 | {
11 | "type": "MIT",
12 | "url": "https://github.com/maxkostinevich/jquery-multifield/blob/master/LICENSE.txt"
13 | }
14 | ],
15 | "homepage": "https://github.com/maxkostinevich/jquery-multifield",
16 | "main": "./jquery.multifield.js",
17 | "repository": {
18 | "type": "git",
19 | "url": "https://github.com/maxkostinevich/jquery-multifield.git"
20 | },
21 | "bugs": {
22 | "url": "https://github.com/maxkostinevich/jquery-multifield/issues"
23 | },
24 | "keywords": [
25 | "jquery",
26 | "form",
27 | "field",
28 | "multi-field",
29 | "multiple-fields",
30 | "jquery-plugin",
31 | "dynamic-fields"
32 | ],
33 | "files": [
34 | "changelog.md",
35 | "jquery.multifield.js",
36 | "jquery.multifield.min.js",
37 | "README.md",
38 | "LICENSE.txt"
39 | ],
40 | "devDependencies": {
41 | "grunt": "latest",
42 | "grunt-contrib-jshint": "latest",
43 | "grunt-contrib-uglify": "latest"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------