Reputation: 573
I am working on some front-end forms using Bootstrap, jQuery, HTML, and a Django back-end. At one point in the form a user is supposed to add "Software" information and then have the option to upload the software file or use a URL to their hosted file. The URL option allows for multiple URL locations that the file could be downloaded from. There is also an option for adding multiple software packages, so if they want to add another, there is a "add" button that clones the form groups and allows the user to put in the information for another software package.
I am unsure of how to make this dynamic where the cloned data will get it's own key-values for using in the back-end, but for now my biggest problem is when you click the Add More Software...
button, the radio buttons being cloned only effect the original radio buttons, and do not have the .switchClass() events binded to them to change their appearance. I can't for the life of me figure out how to get the radio buttons to be bind to the HTML that they are being cloned with. I have attached a jsfiddle to view:
jQuery clone() and Radio Buttons
My question is how would I make this more dynamic so the buttons work with the HTML that is being cloned along with the radio buttons, and how can set the cloned form groups up to be dynamic to grab the values on the back-end?
<div class="software-container">
<div class="form-group">
<label class="col-sm-2 control-label">
* Files
</label>
<div class="col-sm-9">
<div class="btn-group" data-toggle="buttons">
<label id="software-upload-btn" for="software-upload" class="btn btn-default">
<input id="software-upload" type="radio" name="software-upload" value="upload"> Upload
</label>
<label id="software-url-btn" for="software-upload" class="btn btn-default">
<input id="software-url" type="radio" name="software-url" value="url"> URL
</label>
</div>
</div>
</div>
<div id="software-upload-panel" class="hidden">
<div class="form-group upload-container">
<div class="col-sm-offset-2 col-sm-9">
<input type="file" id='software-file' name="software-file" title="" placeholder="No File">
</div>
</div>
</div>
<div id="software-url-panel" class="hidden">
<div class="form-group url-container">
<div class="col-sm-offset-2 col-sm-9">
<input type="url" id="software-file" name="software-file" class="form-control" placeholder="https://www.example.com/my-software-4.6.tar.gz" title="">
<button class="close hidden" type="button">x</button>
</div>
</div>
<div class="form-group add-url-container">
<div class="col-sm-offset-2 col-sm-9">
<button class="add-url btn btn-default" type="button">
<i class="glyphicon glyphicon-plus"></i> Add Another URL...
</button>
</div>
</div>
</div>
</div>
<div class="form-group add-container">
<label for="add-btn" class="col-sm-2 control-label">
Add Software:
</label>
<div class="col-sm-9">
<button id="add-software-btn" class="btn btn-default" type="button">
<i class="glyphicon glyphicon-plus"></i> Add More Software...
</button>
</div>
</div>
And my js:
$(document).ready(function() {
// Actions for URL/Upload button options
$('#software-upload-btn').click(function() {
if ($('.active')) {
$('#software-upload-btn').switchClass('btn-default', 'btn-info', 0);
$('#software-upload-panel').removeClass('hidden');
$('#software-url-btn').switchClass('btn-info', 'btn-default', 0);
$('#software-url-panel').addClass('hidden');
}
});
$('#software-url-btn').click(function() {
if ($('.active')) {
$('#software-url-btn').switchClass('btn-default', 'btn-info', 0);
$('#software-url-panel').removeClass('hidden');
$('#software-upload-btn').switchClass('btn-info', 'btn-default', 0);
$('#software-upload-panel').addClass('hidden');
}
});
// Add button actions
$(document).on('click', '.add-url:last', function() {
$('.url-container:first').clone().insertAfter($('.url-container:last'))
.find('.close').removeClass('hidden');
$('.close').click(function() {
$(this).closest('div.url-container').remove();
});
});
$(document).on('click', '#add-software-btn:last', function() {
$('.software-container:first').clone(true)
.insertAfter($('.software-container:last'));
});
});
Upvotes: 1
Views: 1226
Reputation: 43880
Ok, I did some changes in order to show you the power of this
:
.uplBtn
and .urlBtn
.software-container
class to #software-container-1
var con = $(this).closest('.software-container');
This is how each software-container
is isolated.
$(this)
is that specific button that was just clicked..closest('.software-container')
will start from $(this)
and go all the way up to .software-container
.var pkg = $('#' + con.attr('id'));
it's ugly but it works. This will concat a string of .software-container
id and make it into a jQuery object.Now when you click a button, it will open only the panel it was meant to open. Btw, there's a side effect of cloning if you notice, new clones will begin with the hidden or !hidden state according to the state of the clone before it. Maybe you should create a template #software-container-0
that's unseen and untouched. Or maybe just reset the hidden classes on the new clone only once.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>34884672</title>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet" />
<style>
</style>
</head>
<body>
<div id="software-container-1" class="software-container">
<div class="form-group">
<label class="col-sm-2 control-label">
* Files
</label>
<div class="col-sm-9">
<div class="btn-group" data-toggle="buttons">
<label for="software-upload-btn" class="btn uplBtn btn-default">
<input class="software-upload-btn" type="radio" name="software-upload" value="upload">Upload
</label>
<label for="software-url-btn" class="btn urlBtn btn-default">
<input class="software-url-btn" type="radio" name="software-url" value="url">URL
</label>
</div>
</div>
</div>
<div class="software-upload-panel hidden">
<div class="form-group upload-container">
<div class="col-sm-offset-2 col-sm-9">
<input type="file" class='software-upload-file form-control' name="software-upload-file" title="" placeholder="No File">
</div>
</div>
</div>
<div class="software-url-panel hidden">
<div class="form-group url-container">
<div class="col-sm-offset-2 col-sm-9">
<input type="url" class="software-url-file form-control" name="software-url-file" placeholder="https://www.example.com/my-software-4.6.tar.gz" title="">
<button class="close hidden" type="button">x</button>
</div>
</div>
<div class="form-group add-url-container">
<div class="col-sm-offset-2 col-sm-9">
<button class="add-url btn btn-default" type="button">
<i class="glyphicon glyphicon-plus"></i> Add Another URL...
</button>
</div>
</div>
</div>
</div>
<div class="form-group add-container">
<label class="col-sm-2 control-label">
Add Software:
</label>
<div class="col-sm-9">
<button class="add-software-btn btn btn-default" type="button">
<i class="glyphicon glyphicon-plus"></i> Add More Software...
</button>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script>
$(document).ready(function() {
// Actions for URL/Upload button options
$('label.uplBtn').click(function(event) {
var con = $(this).closest('.software-container');
var pkg = $('#' + con.attr('id'));
console.log('pkg: ' + pkg);
$(this).switchClass('btn-default', 'btn-info', 0).addClass('active');
pkg.find('.software-upload-panel').removeClass('hidden');
pkg.find('label.urlBtn').switchClass('btn-info', 'btn-default', 0).removeClass('active');
pkg.find('.software-url-panel').addClass('hidden');
event.stopPropagation();
});
$('label.urlBtn').click(function(event) {
var con = $(this).closest('.software-container');
var pkg = $('#' + con.attr('id'));
console.log('pkg: ' + pkg);
$(this).switchClass('btn-default', 'btn-info', 0).addClass('active');
pkg.find('div.software-url-panel').removeClass('hidden');
pkg.find('label.uplBtn').switchClass('btn-info', 'btn-default', 0).removeClass('active');
pkg.find('div.software-upload-panel').addClass('hidden');
event.stopPropagation();
});
// Add button actions
$(document).on('click', '.add-url:last', function() {
$('div[id^="url-container"]:first').clone().insertAfter($('div[id^="url-container"]:last'))
.find('.close').removeClass('hidden');
$('.close').click(function() {
$(this).closest('div[id^="url-container"]').remove();
});
});
$(document).on('click', '.add-software-btn:last', function() {
var $div = $('div[id^="software-container"]:last');
var num = parseInt($div.prop("id").match(/\d+/g), 10) + 1;
var $software_container = $div.clone(true, true).prop('id', 'software-container-' + num);
$div.after($software_container);
});
});
</script>
</body>
</html>
I think you wanted to clone the #software-container
and give them each a unique id so you can hook them from the back-end. Going off of the recent fiddle, here's what I got: https://jsfiddle.net/zer00ne/oay1zbva/
I'm not sure if you wanted .clone(true)
but I recall you wanted to retain events...?
$(document).on('click', '.add-software-btn:last', function() {
var $div = $('div[id^="software-container"]:last');
num = parseInt($div.prop("id").match(/\d+/g), 10);
num++;
//var $software_container = $div.clone().prop('id', 'software-container-'+num);
//$div.after($software_container);
$('.software-container:last').clone(true).insertAfter($('.software-container:last')).prop('id', 'software-container-' + num);;
});
});
Upvotes: 2