64 - Dynamic New Forms in a Django Formset via JavaScript - Python & Django 3.2 Tutorial Series

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
right so now we're going to go ahead and dynamically add new form elements in a django form set via javascript now we've already seen this before and it's inside of the admin in the inlines right so in the inline i can actually add as many form elements as i want now it's not really adding a new html form it's really just adding inputs and some data about those inputs so that's actually what we want to do now now before i go much further what i will say is one of the ways you could add more of those form elements is by updating this extra call very similar if not exactly what the admin does so if i say extra equals to two and i look at any given recipe updater i can actually see those two empty elements here and those are fine but it's actually not the route we want to go we want to dynamically add those so i'll leave those in as zero and there's one other glitch that i need to fix and that is adding in this child recipe here so i'm gonna go ahead and do that right there to make sure that all of the form elements are being saved so all of the you know the actual recipe ingredient query set is being saved cool and so now what i want to do is jump back into the template itself and there's something that i can add in here that's going to make things really nice so outside of this for form in form set right underneath it i'm going to go ahead and do div and we're going to put in here the form set dot empty form we're going to save that and we're going to refresh in here now it's an empty form so if i do pasta noodle and one pound and hit save well what happens nothing it actually does not save any of that data it will not go into the database that's because that form is actually meant as a way for me to copy that form element in other words i can come in here and give it an id let's go ahead and call this empty form and also give it a class of hidden that hidden class i'm going to go ahead and add up here and we'll just give it a display none okay and so now if i rerun this that form is no longer displayed to the user but naturally it's going to be inside of here in my element right there okay so initially i'll just leave that class of none being gone right so we can still see it and we can interact with it as much as we want okay so the next thing is to actually create a button that's going to toggle additional of these classes so let's go and do that so button id equals to add more give it a type of just simply button and then we'll say add more okay so whenever you put buttons inside of a form sometimes you run into issues by default in other words let's refresh this page if i hit add more it's certainly possible that it accidentally submits the form so if i do abc and hit add more that could happen now in this case it's not happening because well i didn't give the type of submit i just gave the type of button so it's important that you do add in the type of button okay so now we actually have the basis to add additional forms the actual empty forms but it's going to take several steps to get there and it's all through javascript so you're gonna have to bear with me on this if you've never used javascript before but it's not that much different than python there are some certain syntax things that make it a little different but overall it's very similar to python in this case so the first thing that i want to do is i want to think about how i'm going to be adding this form well the form is going to be responding to me clicking on add more right so if i click on add more it should add more forms simple enough so what that means is then i need to listen or attach some sort of event to when this button is clicked when i say event i mean literally the action of a button being pressed or this particular button being pressed or this html element being pressed i want to then copy this html element all through code right and so let's go ahead and do that now in python you probably know that the something like add more btn would be declared like this so this would be the variable of admore btn inside of javascript we use either const let or var in front of that variable so const means it's a constant and it will never change and so in this case it definitely will be a constant this is actually important in javascript it's not important in python python doesn't have constants that work like this in front of variables in any case we can now want to grab this element now there's not very many identifying factors to this element other than this right here certainly it's a button but there's a bunch of other things that are buttons and certainly it's a type of button but there's other things that have a button and so what we want to do is we're going to go ahead and grab this by its id we want to look for this element by id now to do this there's a command called document.getelement by id and then you literally copy and paste what that id is and so this is how we actually can grab this element inside of javascript that's it right and so from that i can actually add in what's called an event listener and there's all kinds of event listeners the one we're using is just simply click and then in here we want to call some sort of function okay so a function in javascript so in python we define our functions as define you know something like add new form and it's going to take in some arguments and then you know it would return some value or do something like that okay and so javascript is not a whole lot different than this but instead of def you would just do function and then instead of a colon here you would use curly brackets and we don't need a return statement in this case but you can also return values in a javascript function so that's it that's really just a plain old javascript function and so since it is a named function i can actually pass it in here now there are functions that are not named that you can actually do something like this this is called an arrow function or fat arrow function an anonymous function that is a little bit more advanced and something you'll see from time to time but for now i'll just use in the name function and there we go so we have this add more button with an event listener and a function called add new form and so what i'm going to do here is i'm just going to go ahead and type in my argument so i'm just going to say args here now in python we would go print whatever those rs are to find out what arguments come in to this function by default based off of this click event listener and so i'm actually you in javascript you can't use print of course you have to use console log right so console.log is the same thing as print in python okay and comments are slash instead of hashtag you know all of these little things that end up making it kind of frustrating to change between languages but once we do all this stuff you'll see why it's really really good okay so now that we've got that let's go ahead and refresh in here i'm now going to click on this add more button several times remember i said console log well one of the things that you'll see over here is the console this is the javascript console of course if you don't see that you can go to view and developer and javascript console click on that um in this case it actually toggled it down for me but if i actually look at it again it'll bring it back up and there's my console and so i've got all of these things coming in here these are all of those events so if i refresh again hit add more it's showing a bunch of events now if i hit save it shouldn't actually show those events right i hit save it doesn't show anything in fact it actually reloaded the page for me i tried to do add more i hit save it literally reloads the page because i'm saving all the data as it says data saved but what happens with this event listener is i can just add a new form or at least i am calling this event so this argument is actually called an event add event listener not that surprising maybe that when a click happens it actually gives that event to this form itself and so all i'm going to do here is add a condition called if event then we'll do event dot prevent default okay that's it now this event.preventdefault means that if you accidentally called this submit this would not allow it to be submitting now there's a lot of things that we could talk about here i'm not going to talk about those things right now but overall now we will no longer see a console log and the page should not refresh like it does when i hit save and you'll notice that by the little flicker up here yeah okay cool so we have the basis of two solid elements what's the next step here so after this is clicked now add a new empty form to our or rather form element say to our in html form that's what we want to do so how do we do that well we have amg form an example right here so i can have a new constant in here and say empty form element and it's going to be now document.getelement by id again because we have an id here and i can grab that element cool and so in this case what i'm actually going to do is bring this element into the function itself now one of the things you hopefully are wondering is like what's this document thing referring to well that actually refers to the final rendered page that's here so notice it says doctype html it's referring to this entire page here so anything that's in theory anything that's on this entire page the javascript should be able to grab it by using document.getelementbyid or git element by something else as well so it's very often that that isn't the case but for what we've done here we haven't done very many advanced things it's certainly the case so this actually grabs that form for me and what i can do actually is i can clone this form or copy that entire div by doing dot clone node and passing true in here so this will be a copy of the original one and so what i want to do now is i want to remove the class if there is any class in there so i'm just going to reset that element basically and we'll go ahead and take the empty form element itself the actual constant here and then on there there's a bunch of instance methods that we can run something like set attribute and the actual html attribute that we want to set so in this case we'll say class and i want to set it equal to hey the same class that we have here which is just simply ingredient form like that so now it's going to set that attribute so in theory it should actually remove the class that's in here and that's it next what i want to do is actually want to add this form somewhere well where do i want to add it well probably at the end of the for loop of my current ingredient forms or at least right before this button here i'm actually going to add it to the end of my current form list so what i'm going to do here is say class equals to maybe the ingredient form list or just ingredients it really doesn't matter so much of what you end up calling this so notice that i use class i could use class or id now i'm going to stick with id for now to make things simple but i'm going to go ahead and grab the id of it and yet again i'm going to add a new constant so this constant i'll set above the empty form element and we're going to call this our you know form copy target and it's going to be document.getelement.com by id again and it's that right there in this case of course we're not cloning it i do not want to duplicate this target instead what i want to do is just append the new duplicate okay so far so good this is uh hopefully not that hard yet so we refresh in here and if i go into console i have no errors if i see something like i say that gibberish in here if i see something like this this means that i have errors and i need to fix them oftentimes you can actually see what the errors are right inside of that console right which in this case is just showing that gibberish so let's go ahead and go back and get rid of that gibberish and let's go ahead and try out our new form here a refreshing here and i hit add more add more add more add more hey that's pretty cool so i'm gonna go ahead and inspect the element on any of these and what i should notice is the class names being ingredient form that's great the empty form itself is not showing that class name so i i do want to get rid of what that empty class name should be all right so the empty one should be simply hidden and that is going to be our initial class and there we go so we've got our gradient form class let's try this again let me close down the elements here i hit add new add new add new great now it doesn't look great i'd say in relation to what the other form did right so the other form being what we actually had in our form set as p tags but it is close to that and so what if we actually decided to say dot as p here right can we do that so it's an empty form add more hey what do you know the same sort of actual feature existed here so if you're using django crispy forms you can still use crispy there but we actually run into a huge problem with where we're at right now and i'll go ahead and say pasta noodles some quantity in here um now notice this it's not actually giving us the correct value we'll talk about that in a second um and then i'll go ahead and hit save and let's just refresh in here things are empty okay so there's several things that are challenging for this number one it's copying this entire html element which means that it's essentially doing this notice the id is still staying there the thing that is changing is simply the class right and that's good so the first thing i need to solve is the attribute of the cl the id for now i'm just going to go ahead and give it an empty id that solves the challenge of that duplicating the data as well and so we come in here again hit add more now it's empty data that's good but if i go to save it it doesn't save anything and so let's go ahead and check our views maybe there's something in the views that that should show me that it is saving something so in here of if request dot post or request.method equals to post let's go ahead and print out request dot post okay see what that post data is i'll add another ingredient pasta noodle hit save go back in take a look at the terminal and here's our post data okay so now we see where the challenge is now this might not be a challenge that you've ever recognized but here it is right here we've got form dash underscore underscore prefix dash you know all of that stuff now let's actually take a look at that same data in a recipe that does have something we could edit which is just another recipe that i actually have ingredients with i'll just go ahead and save it and take a look now so if we look in here now we see no prefix data in here now this is coming from the actual empty form itself this form right here and if you're starting to feel like this is this is overwhelming just bear with me you could stop if you're feeling a little overwhelmed because we're going to solve this in a much easier way with hdmx in a little bit this should highlight why you should use hdmix depending on where you are in your development cycle but the challenge here is all of the things that come in with this so all of the features and attributes of an empty form do not actually lend itself or tend to lend itself well for just dynamically adding data it's actually made for that but it requires a number of items in javascript to make it happen so what that means is that the first thing i need to do is i need to update my actual form management form that we created so i need to update this data right here so let's take a look at that data i'm going to go back into the other recipe with no ingredients so if i inspect the element here or view the page either one i still see the management form data in here so it's definitely still showing me this and notice that the total forms is zero it's literally always going to be zero until i change it but the nice thing is it does have its own id and this id will stay this way unless you modify it in some other capacity so that means then that i can actually come in here i can grab what that id is so we'll go ahead and say total new forms equals to document.git element by id yet again and it's grabbing literally that id here okay and so what we want from here is we want to update what this value is going to be right so before i can update what that value is i need to actually know how many items are in the form list itself how many items are in here this is where we can actually count the number of classes and this is also why we would want to add our empty form element with the exact same class that's on this one okay so how do we do that now what we want to do is we're going to go ahead and say const current ingredient forms and this can now going to be document.git elements this is a plural now by class name now when you have an id it's usually specifically about once element that's best practices is you only assign one single element to that one single page on that whole thing classes on the other hand are many elements can have classes now if you know css you probably already know this this is just adding on top of that with javascript so what this is going to do is it's going to give me every element that's in there by default and every hidden element that we added in through javascript so in other words i can actually console.log what that length is right so let's go ahead and do that inside of our add new form here so i'll go at console log the element itself so the variable and then dot l e n length save that we refresh in here add more add more go to our console and now it's showing the length it only happens at the beginning so it's kind of counting behind us a little bit so it starts with zero one two right now if we go back to our other one that actually had those values already it's going to count and add on top of that so one two three is where it started then we added one which should be four then we added one more five so that's actually how we can get the current length of these items which means several things first off we can now say i'm going to do let being the current form count is equal to that length and then i'm gonna add one because this is adding one it's gonna update the current form length to one more essentially right so it's gonna get that element and it's going to add one more it'd probably be best to have this in the function itself to actually get the document element there because if i somehow added these more dynamically in another way this would at least give me what that count is so let me go ahead and give it a constant here and so now what i need to do is on this form element i want to add this id so i'm going to use some string substitution here the string substitution inside of javascript is very similar to f strings but just bear with me on this one so it's dollar curly brackets dash and that's it so we're going to add that id and it's going to be based off of this current count variable which should be an integer so now if we save it let's go and refresh in here i'm going to go to my new one and we'll hit add more i'll inspect this element here and on the actual div class itself it gives me a new id inside of here i still have these prefixes everywhere which we'll solve in a second but it will give me this new id and it's correct form one form two and so on so that's good so now pretty much the final step we need to do is we need to change all of these prefix values and here to whatever that id is okay and so i know it's plus one because if we go to one that already exists oh maybe it's not plus one maybe it's actually zero maybe it's the actual index value right so this is where just you know doing some research on our own can help that a lot it's going to be the index value so we actually want whatever the current length is that's going to be the next form iteration okay cool so now we're going to use a regular expression and i'm just going to go ahead and copy and paste this this is the regular expression it has that prefix in there and we're going to use this regular expression to just simply replace things that are inside of this empty form element this copy of this empty form element so this is really a copy empty form element and let's actually name it as such so it's a lot easier to reference later so now inside here we use a command for the inner html and we're going to go ahead and just say enter html dot replace this regular expression here and we just want to replace it with whatever the current form count is kind of okay so it should replace this entire string here which going and adding a new one will show us what that would look like here it is form 4 and so we should see that prefix changing we save it and we refresh in here let's go back to two with none in there i'm gonna add one say pasta noodles unit and we'll give it a pound we hit save we've got some issue it's not showing up necessarily it's going to refresh in here and let's look in i here still not working okay so back into our views we did print out the post data so let me scroll up a bit and so what we've got is form zero we still had the total forms also being at zero okay so the last thing total new forms this is where we're going to have to set this value before we append that for the inner html set this to set attribute value and it's now going to be whatever that current count is plus one so that's the actual addition that we need okay so let's try it again add one more pasta noodles one pound hit save refresh this page and sure enough there it is refresh this one and sure enough that there it is cool all right so let's go ahead and add a few more you know whatever you want in here and so on and so forth so it's great but one of the things that you might be noticing is the form itself is not dynamic and we can absolutely use javascript to make it dynamic but now we're getting into this whole heap of a brand new programming language that you may or may not want to spend time on i personally really like javascript and i will spend a lot more time on it in the future but if you're not ready to dive into that or you just want a faster way to do this exact same dynamicness that's something we want to do with htmx and we will start doing it in the next one but the general idea here is adding dynamic elements traditionally is through javascript because it's really the only code that can run in the browser because the browser itself will run javascript so if we go into view developer and the javascript console again we did console log things in here but i can also run actual javascript code right in my browser and you may have seen people do this before where it's like oh well they just hacked my website well no but it just seems like they did right so document let's say body right so notice that it's actually selecting that so this is actually a new another good place to grab some of these elements let's go ahead and just paste this in here and now i can actually test a lot of these things out right and so if i did run some of this code i want to see what's happening here that would be a way to do it and notice that it gives me some of those values and i can investigate even more as to what's going on so the javascript console is really really useful for those reasons but it's just a whole other layer of technology that we would have to learn now what we're going to move on to is the tool called htmx that actually does so much of this leg work for us and all we have to do is implement some things in our views that are similar to this i'm going to go ahead and get rid of this request post method here and just leave this as is of course if you have any questions let me know otherwise [Music]
Info
Channel: CodingEntrepreneurs
Views: 22,797
Rating: undefined out of 5
Keywords: install django with pip, virtualenv, web application development, installing django on mac, pip, django, beginners tutorial, install python, python3.8, python django, web frameworks, windows python, mac python, install python mac, virtual environments, beginner python, python tutorial, djangocfe2021, digitalocean, production, python, django3.2, web apps, modern software development, trydjango2021
Id: s3T-w2jhDHE
Channel Id: undefined
Length: 28min 26sec (1706 seconds)
Published: Sat Aug 14 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.