Reputation: 283043
I'm building a dynamic form. It looks like this:
When "Add destination" is clicked I want to add another section, "Address 3". If "Remove destination" is clicked after that, "Address 3" should be renumbered to "Address 2".
I've done things like this before, but it always feels like a big mess of HTML and JavaScript. I'm trying to figure out the best approach. Here are some possible solutions:
Wrap each section in a <div>
. When "Add destination" is clicked, clone the last section. Loop over each input in the clone, update the name
and id
attributes. Wrap the address # in a <span>
and update that too. Add some more JavaScript to initialize the date and time pickers and validator.
Build the entire DOM with JavasScript/jQuery.
Put the entire chunk of HTML into a JavaScript string. Use placeholders for IDs, names, and numbers. Use some basic string replacing to increment them as necessary.
Use a client-side templating language like Jade that will only be used in one or two places throughout the entire project.
None of the solutions are particularly appealing. How would you approach this problem and why?
Upvotes: 2
Views: 487
Reputation: 18117
this is a quick hack but reliable in most conditions
http://jsfiddle.net/techsin/7pceP/
var s = $('.sample'), c= $('.container'), total=1;
$('.Add>a').click(function(){addSample();});
function addSample() {
var clone = s.first().clone();
clone.find('.Remove').toggle().click(function(){ rmvSample($(this)); });
clone.find('.num').text(++total);
clone.insertBefore(c.children(":last-child"));
}
function rmvSample(x) {
total--;
x.parent().remove();
updateIndex();
}
function updateIndex(){
$('.sample').each(function(i){
$(this).find('.num').text(i+1);
});
}
Upvotes: 1
Reputation: 283043
So, what I've done is stuff an entire Twig template into a JavaScript string:
var template = {% filter json_encode|raw %}{% include 'bookings/address.twig' %}{% endfilter %};
The template contains some Underscore/lodash template variables in it, like <%- index %>
, which I use in all the IDs and names. Then I render it out as needed:
_.template(template,{'index':addressCounter++})
This way I can take full advantage of the Twig templating language and use its form builder inside my template. I had briefly contemplated using Nunjucks instead of lodash, which is basically just Twig for JavaScript. I figured it might get confusing to use Twig inside of Twig, however, and I didn't want to include a full runtime when all I really need use a few simple variable substitutions.
Seems to be working pretty well so far.
Upvotes: 0
Reputation: 5565
How: You could initialize a global var with value 1 and each time the add click handler is called, the variable is incremented and the name is formed by "Address " + globalCount. Similarly, when the remove destination is clicked, the global count is decremented.
Why: Very little logic, although global variables are not the greatest at times, it reduces other complexity that would arise from other solutions and is pretty elegant.
Other option: When creating the first destination section you could provide it with a data attribute $(destinationToCreate).data('count', 1).
I would assume that these destinations sections would be created within some kind of container and that they are of the same structure so that when you're creating a new one something like this would be possible:
var newCount = $('#destinationContainer div').last().data('count')++
Upvotes: 0