Hi everyone,
Almost a year ago I started a tutorial series on formsets, with the first part discussing the foundations of how forms and formsets in Django actually work. Today I uploaded the second part of the series, which deals with dynamically adding/removing forms with JavaScript.
You might be thinking ‘do we really need a tutorial series for formsets’? Well probably not really, but grappling with formsets also provides a nice entryway to a lot of stuff. The series touches on a range of different concepts, like connections between ‘Django in the shell’ and what’s output in the browser, or how you manipulate the DOM tree with JavaScript while playing nicely with Django.
I’ve tried to make the tutorials as beginner-friendly as I can. If you know a lot of Django/JavaScript already however, be aware that they might be overly verbose.
I especially found the second part to be a huge challenge since I didn’t want to make too many assumptions JavaScript proficiency. Any feedback about it is greatly appreciated
Both tutorials are over at datalowe.com. I hope you’ll find them interesting!
(the site itself is also created with Django, and though it’s basic I’ll gladly answer any questions about it as well )
2 Likes
Very nice!
One topic I didn’t see covered or in your roadmap is the use of the empty_form
attribute to create the template for adding new entries.
We actually use that two different ways. We have some pages where that is rendered in the template in a hidden div to be referenced by the JavaScript, and others where we’ve created an API for the client to request a new blank row be supplied by the server. (We use the latter when that blank row needs to be customized for whatever reason, such as having a context-dependent drop-down.)
1 Like
Very nice indeed, thanks!
Couple of suggestions:
. favour insertAdjacentHTML over individual node/attribute generations.
. to make up for the absence of individual element references since you use insertAdjacentHTML, use event delegation. → one event that always listens, no need to add/remove listeners on the go. More efficient memory-wise.
. document.getElementById → document.querySelector ?
. consider wrapping your code in a singleton? for example (function(w,d){…})(window, document); might be useful later on and is generally more clean (no polluting the global namespace) and secure (none of your stuff in the global namespace).
One topic I didn’t see covered or in your roadmap is the use of the empty_form
attribute to create the template for adding new entries.
Thanks for the tip! I’m learning as I go, so I didn’t know about using empty_form
. (anyone else who hasn’t used this might find this short guide by Marcelo Canina interesting) Using the ‘empty form’ to generate additional input sets seems like a clean method that’s much quicker to implement. I like having the second tutorial show how to go about adding a new form from scratch even though it’s inefficient, but I think I might add something like a ‘tutorial 2a’ that explains how to use empty_form
instead.
favour insertAdjacentHTML over individual node/attribute generations.
Cool, this is another option that I didn’t know about. While I can see that this would decrease the amount of code and possibly slightly increase performance, I’m not sure about using it for the tutorial. There is a pedagogical point in forming the new DOM elements and modifying them in multiple steps, to give the (possibly not very DOM-proficient) reader a feel for creating a node, fixing it up, and then linking it up to the DOM tree. Or at least, that was my intent.
to make up for the absence of individual element references since you use insertAdjacentHTML, use event delegation. → one event that always listens, no need to add/remove listeners on the go. More efficient memory-wise.
I’m not sure how you mean here, the only event listeners that are used in the tutorial are for the add/remove buttons, and these are always the same. I suppose I could use event delegation (described eg here for anyone who’s new to this) by putting a single handler on the body instead. But this would mean that I’d have to add quite a lot of explanation regarding how event delegation works, and might be overwhelming if the reader isn’t very familiar with using events at all.
document.getElementById → document.querySelector ?
Thanks, I think you’re right. A benefit of getElementById
is that its name is more expressive for a newbie and it might make more sense to any reader who might not have used CSS much, though I would guess that’s a small minority. On the other hand, querySelector
is broader and is probably what people new to javaScript should get into the habit of using if they can. When I investigated their differences it seemed like the only real advantage of using getElementBy...
methods is if you need a live node list. I’ll see when I find the time to change this.
consider wrapping your code in a singleton?
This is something that is obviously a very good practice, while polluting the global namespace is very bad as a habit. It’s something I considered but then abandoned, since explaining the singleton pattern (and the multiple ways of implementing it) is too advanced for what I was aiming for. My main goal with the tutorial was to show how one can get started playing with JavaScript in a Django context, and that it’s possible to do stuff even if you don’t know much about best practices. I’ll add this as an additional exercise suggestion at the end of the article.
Thanks again