Skip to content

Instantly share code, notes, and snippets.

@ahmed-musallam
Last active January 23, 2018 19:52
Show Gist options
  • Save ahmed-musallam/6c07d1797934ec702a7e9eaff0f8f77f to your computer and use it in GitHub Desktop.
Save ahmed-musallam/6c07d1797934ec702a7e9eaff0f8f77f to your computer and use it in GitHub Desktop.
Multifield example with bootstrap and jquery ui, see it here: https://jsfiddle.net/bdrp0eow/
.multifield form {
margin: 0 auto;
max-width: 750px;
}
.multifield .margin-1rem {
margin: 1rem !important;
}
.multifield .fieldset-container {
padding-left: 0px;
}
.multifield .multifield-field .move,
.multifield .multifield-field .delete {
color: grey;
}
.multifield .multifield-field .move:hover,
.multifield .multifield-field .delete:hover {
color: black;
}
.multifield .multifield-field .move {
cursor: move;
}
.multifield li.row.multifield-field {
padding-top: 1rem;
padding-bottom: 1rem;
border: 1px solid #ced4da;
border-top: 1px solid #ced4da;
border-radius: 5px;
}
.multifield .row:last-child {
margin-bottom: 0px;
}
<!-- Required libraries, you can include them somewhere else on the page -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/open-iconic/1.1.1/font/css/open-iconic-bootstrap.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<!-- Multifield container -->
<div class="multifield" data-multifield>
<!-- field template -->
<script type="text/template" data-template>
<li class="row multifield-field align-items-center margin-1rem" data-field>
<div class="col-10">
<div class="for-group row">
<label class="col-sm-2" for="text">Option Text</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="text" aria-describedby="textHelp" placeholder="Enter Text">
</div>
</div>
<div class="form-group row">
<label class="col-sm-2" for="val">Option Value</label>
<div class="col-sm-10">
<input class="form-control" type="text" class="form-control" id="val" aria-describedby="valHelp" placeholder="Enter Value">
</div>
</div>
</div>
<div class="col-2">
<button type="button" class="btn btn-link delete" data-delete>
<span class="oi oi-trash delete"></span>
</button>
<button type="button" class="btn btn-link move" data-move>
<span class="oi oi-move"></span>
</button>
</div>
</li>
</script>
<form>
<!-- field template is added under this UL -->
<ul class="fieldset-container" data-fieldset-container></ul>
<!-- form controls -->
<div class='margin-1rem'>
<button type="button" class="btn btn-primary" data-add>add</button>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
(function() {
var SELECTOR = {
template: '[data-template]',
fieldsetContainer: '[data-fieldset-container]',
addBtn: '[data-add]',
deleteBtn: '[data-delete]',
moveBtn: '[data-move]',
field: '[data-field]'
}
function Multifield(el) {
var multifield = this;
multifield.$container = $(el).first();
multifield.template = multifield.getRequiredChild(SELECTOR.template).html();
multifield.$fieldsetContainer = multifield.getRequiredChild(SELECTOR.fieldsetContainer);
multifield.$addBtn = multifield.getRequiredChild(SELECTOR.addBtn);
// setup sortable
multifield.$fieldsetContainer.sortable({
handle: SELECTOR.moveBtn,
cancel: ''
});
multifield.$fieldsetContainer.disableSelection();
multifield.$addBtn.on('click', function() {
multifield.add();
var $delete = multifield.getRequiredChild(SELECTOR.deleteBtn, SELECTOR.field)
$delete.off('click');
$delete.on('click', function() {
multifield.delete($(this).closest(SELECTOR.field))
});
});
}
// get child from selector, throw error if cant find it
Multifield.prototype.getRequiredChild = function(selector, parent) {
var $el = $(parent).length ? $(parent).find(selector) : this.$container.find(selector);
if (!$el.length) {
throw new Error('Could not find required child ' + selector)
} else return $el;
}
// add new fieldset to the bottom of mutifield
Multifield.prototype.add = function() {
$(this.template).hide().appendTo(this.$fieldsetContainer).fadeIn(150);
}
// $el can be an index, or the element to be removed
Multifield.prototype.delete = function($el) {
var isNum = jQuery.isNumeric($el)
$toBeRemoved = isNum ? this.$container.find(SELECTOR.field).get($el) : $el;
$toBeRemoved = $($toBeRemoved);
$toBeRemoved.animate({
opacity: '0',
height: '0px'
}, 150, function() {
$toBeRemoved.remove();
});
}
// expose multifield to global scope
window.Multifield = window.Multifield || Multifield;
})();
// start multifield
var m = new Multifield($('[data-multifield]'));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment