Dynamic Bulk Creation - Building SaaS with Python and Django #98

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi welcome to the building sas with python and jago my name is matt lehmann and on this stream we work on building django applications and we're going to work on my homeschool app that i've been building stream after stream we're going to continue on that process this evening the plan for today is to work on a bulk creation page that is going to use some javascript to dynamically add more items to a certain page it's bulk task creation which we're going to get to here before we get into that though i do want to thank my patrons on patreon if you want to support me you can at patreon.com mblament and i want to thank rupert andrew patrick eric phillip and a new patron miguel thank you very much for your contributions it's super helpful for helping me to financially support the work that i try to do for the django community cover podcasts costs all this other stuff that that comes along for that ride so i greatly appreciate it there are other ways you can get in touch with me as well you can go to my website which is linked above you can find articles that i write there about django um there's my handle on on twitter is mb layman if you'd like to follow me i also take this content and post up on youtube so if you find this stuff valuable and you can do me a favor okay give me a like or a comment on youtube that definitely helps and helps others find this material so that they can learn some about django themselves so that's uh the intro and let's get into the actual activity for this evening i have some customers on my site and the site's fairly new service it's been serving my my wife as a homeschool application to help my two children get their education at home and i have some initial customers and i'm starting to get some good feedback about here are things that they are looking for as in addition to their um their own needs that could make the service more valuable and one of those requests is coming from one of my beta customers and she was asking for an ability to create tasks in bulk i already have a bulk task creation page but she was really looking for something a bit more dynamic so that she could add more than the amount that i have so what i'm going to do is i'm going to start by showing you what that feature looks like today so you can have an understanding of what the page is and then we're going to talk about how we're going to extend that page to have the functionality that she's looking for so i'm going to begin by starting up the web application server and we'll go to this page and we'll navigate to the site it's at home school uh it's at poor 5000 excuse me and we can go to the dashboard and oops that's not that's not what i meant that's my um it's my like management dashboard what we want to do is come to here which most people most people don't see out their dashboard page and we want to well rats i last week i had a school year that was about to end and it looks like it ended and so in order to like not waste time building a school let's just extend this school year by a few another couple of months or so if it let us because there's a maximum limit so we'll see if we can get it out to june and kick that down the road nope uh it's starting to run out of running out of runway making a school year that's longer than um 500 days so okay got to about bought myself another month and then i'll really have to buckle down and figure out a way to quickly spin up a new test site so in a school year there's an ability to create courses this is all about managing a whole school and managing it per student and the course is a collection of tasks and those tasks are what the students are asked to do from day to day so when a when a user is building up a new course they might get a course page that looks a little bit like this it's a little busy probably need to clean this up later but they can go and the first thing they can do is add a task and on the add a task page you get this option of using a bulk create and so this is the page that the user has had comments about it'd be really nice to be able to do more than what's here because the my my spouse also requested a bulk create feature and i said hey look i can make this really quickly if i do um you know like a set of 10 and that's just static you get that you can add it and then it'll you can add 10 at a time and for her needs that that worked um but the the request from the beta customer was hey could we make it so that there's more than 10 at a time like either with an add button or add more and so i've been thinking about how i want to do this and we're going to work through that and i should note that you know the the goal of this is to teach people it's to make progress on a site but also in that process teach people about django so if you have any questions you're free to ask me anything about python django or web development and i will do my best to answer those questions um so our link for this evening is this uh this issue so conveniently clicking access there you can check it out and i have been thinking about how how to implement this so her initial request was looking for like a button and that's pretty common i think it's common a common request because it's a common way that people think about it if they want to add more they want to be very proactive but i want the experience on this site to be really slick so what i've been thinking instead was wouldn't it be nice if when you got to this last page and you're entering into the 10th item here at some point maybe after a delay more just kind of pop in below you and we can do that with some javascript there's some stuff that we can do to kind of trigger that and so i think that's the the path i want to take is make sure that this gets uh connected to some javascript code so that when you get to this last item and somebody starts typing there will be some code fired off to to go add more form items here so before we do that though we need to talk about a little bit about what this page particularly is how does this work at the django level this page uses something called a django form set and if we inspect the element and look at some of these items we can see air aspects of it that will help make it clear what we have to do for form sets a way if a way a form set works is it is as the name implies a set of forms so each one of these rows corresponds to a single form and django will treat them all as a collection and then have a little bit of management on top that we'll talk about and so when you're on this bulk creation page a form set is allows a user to create a lot of items all at once go through the same machinery as the normal form system and then um create those in at a bulk create or some other kind of mechanism and that is what we need to handle here and the real gotchas with form sets there aren't that aren't too too many but there are some things that we have to be aware of and one of those is a management form so if you looked i inspected this first form and while we're here let's take a take a look at it so it has an id on it that is this id form 0 which is important more important for for regular web forms though is the actual name attribute browsers don't actually care about the id it doesn't submit those in post it really cares about name and so it says form 0 description so each one of these forms maps to a task that's that it's trying to create and so it is going to attempt to create a a task a course task and by giving it a zero in this naming scheme of form zero it's so it's able to associate all this data so if we inspect the text box we'll see that if we come over to this number field we'll see that it says form zero duration if we come to this graded box it'll say form zero graded and then so on so we come to the next one and as a zero index thing and it says form one um there it is right there form form one description and and so on you get the idea um so in order for django to know how many forms to process though there is a hidden uh management form that is at the top and so at the top of this template before this first form field and before the titles and all that stuff well maybe i put it after it doesn't really matter there you can see them as these hidden fields one is the csrf middleware token which is that's a security feature which we're not really going to dig into so that's that's just something that has to be there but you can see that there are um a total number of forms there's a maximum number of forms and minimum number forms and initial and so on and so what we need to do is uh populate if we're going to dynamically do this we we want to change this value right here so there's a 10 here because that's how many i chose to render on this page so as we add more things to this which we'll do with some with some javascript and some actually a library called htmx is my hope we will have to also modify this total forms thing if you don't do that django throws up an error and says you've tried to submit more forms than i anticipated and i don't know what you want to do so no that's something that we have to be aware of in this process so my flow for this issue that i think i've been doing thinking of in my head is did i write it down here i didn't so these are a bunch of items that we'll have to consider but um let's let's sketch out in the issue what i think we need to do so um in the so for the actual flow in the template rendering um we want to make the last form special the last form is the only one that we want to have go and actually populate more form fields like it we wouldn't want to we wouldn't want to come in here and enter some data into this form first form field and then have it like jump at the bottom that's kind of a crummy experience so that's not what i want to do so we want to have that last form is special and it's special because it needs some extra attributes so we what does that mean to be special there um it's uh we need to connect connect htmlx which is the javascript html markup library that we're going to use to actually do some requests so this may not be the this may not be the most efficient way i'll say to do this dynamic stuff but i'm not using react i'm not using vue.js i'm not using any of these i'm not i'm trying to avoid bringing in a really heavy javascript tool chain to do some rich client interaction hdmx kind of exists in this nice middle ground that works pretty well with server side rendered templates which is what i'm doing so what we'll do is we'll add some htmlx stuff and the the flow that i'm having my head is that when the the person types in that last box when after they typed it's going to trigger the htm x code and that code is going to issue a get request and it's going to go to the server and say um give me another set of five forms please well it's not going to ask politely it's computer but you get the idea it's going to go get more data and it'll be rendered html and we'll process it in such a way so that the form attributes that i already highlighted the form 0 description form 1 description and so on will be properly configured based on some index that we provided so we by knowing at render time what the last form is we can also know what the next form should be or or we'll handle the the indexing one way or another and so it will ask the server for another set of five things to add or whatever number we pick maybe it's 10 i don't know we'll play with it and the browser or the server will return response that says okay here's a fragment of html drop this in there and insert it after that that blast form so that's kind of the next step so we have to have a view that will render more forms so that's that's important um and i'll call it uh actually i'll call it an htmx view there's no there's not really such a thing but it's going to be very specifically for htmlx so that'll help give some clarity of what that's all about so this is going to render more forms as a partial and the browser will must insert that partial after the last form okay so but there's there's that management form there's that total element as well and that's where we need to have a little bit of extra javascript code so uh what i actually before this this um stream this evening i went and was doing research on the htmx documentation which we're going to bring up and i'm sure we're going to make heavy use of to get all the attributes right and one of the things that htmx can do is that in that view response up here that we can not only get the html partial data that we want to insert but we can return some special response headers and those response headers can actually trigger an event a browser-side event the browser is really good at handling event kind of code function callbacks all that sort of stuff and so we want the response to trigger a i don't know i'm not sure what to call it manage let's call it the that stuff at the top that's hidden is the management form so what's called a management form update that's that's sort of what needs to happen on the client side and really that that event all it needs to change is we need to change the id that says um hey terrible goss welcome back glad you're here um we we need to change the event sorry we need to take the event and change that hidden management attribute for total forms and update it for this new count so if we've added five more forms to this bulk creation form then we want to update the total from 10 to 15. if we're you know the math checks out which is not a hard thing to do but we've got to wire up a little bit of javascript to make sure that works otherwise django will reject the entire thing so this is the basic flow that i've had in my head for how we can do this dynamic bulk creation stuff in the app i have a feeling there are a whole myriad of gotchas that are probably a bunch of shortcuts that i took for actually building out this create view this bulk creation page the first time that we'll have to correct but this is the the path that we're roughly going to follow um so that's my plan all right hopefully that makes sense if you have any questions about this and maybe now is a good time to like reintroduce htmx because hdmx is a pretty split library um and but it's not i don't say it's super popular yet i i don't know i think it's really cool i hope it does become popular because i think it's a really um a nice way that to use javascript that doesn't involve a ton of javascript and as someone who likes to spend his time in django and python this is really appealing so here's hdmx in a nutshell and the x part is like it's trying to it's a play on let's take html and make it dynamic which is what i don't i don't know the x makes it edgy i have no idea um but uh you can see here's an example of like here's a normal get request so an anchor tag can do a if you give it an href it'll go to slash blog and do a get request in the browser that's just the default thing if you are have a form and you set method equal post and you hit submit then you do a post request and send some data what htmlx unlocks is the ability to use other http verbs there are a handful so there's uh get and post are the ones that we all know of but there's also delete and put and patch and options and there's a head and there's there's a handful of them that and most of them though like you you can't in regular html markup access these http verbs aside from using javascript so if you use javascript's fetch api you can make these kinds of requests but those aren't immediately available directly in markup and this javascript library what it does is it makes those available to you as as a different way of of handling stuff and it's not immediately obvious here but um this is this is an example of how this works is with some attribute markup in this case an hx post it's sending is saying send a post request actually he's got god this says it better here than i could say it so when a user clicks on this div issue an http post request to clicked and use their content from the response to replace the element of parent div in the dom and using an outer html swap so it's really cool for like doing quick finding um like swap replaces and stuff and there's a bunch of other features that we're going to take advantage of what's nice about this is that essentially i can use a django template and django template markup to drive dynamic behavior that i want the the client to do that's a little different so where you might in the past have you know your template an html code in one area and then a script block that is going to get elements by id or use jquery or do some other technique to go reference the tags that are in the html this says let's put the the kind of code for the javascript really close to the markup so you can definitely see it so that's what htmlx is all about and that's why um that's what we're going to try and use i've already used it in some parts of my project and i want to get good with it because i think it's really powerful or i see it as being really potentially powerful and i just haven't done a ton with it yet the stuff that i used it for was pretty vanilla use cases like deleting a row and then deleting that html okay so where where do we go let's look at some code um yeah let's look at some code we want to start with this bulk create page which is probably going to be how big is the htmx library good question i think it's pretty tiny um i don't know what it is minified sorry um let's see i've got a version and i it's it's even a single file library they talk about it here um so you can use it as as just like from any sort of cdn um in in this case this example it's using from unpackage and i can i can give you a quick answer because i actually committed to my library so i didn't have to depend my repo so i didn't have to depend upon cdn being available although how often do cdn's going go down not very so in my static stuff i probably have js there it is and so let's do d ush so 28k communified so really not very big and um you know that's not that's not compressed either so that's that's uh that's that's pretty good yeah good enough i agree um so let's go to let's go find the the bulk view that exists let's look at the template see what i'm actually about to get myself into because i have a feeling i did take a lot of shortcuts to do some of this stuff um here's a bulk create page it how many okay i did at least have it programmable here so that i'm not actually like hard coding 10 i just say extra 10 to do the initial creation so that's good news and i don't know that this course form set is used well okay maybe it is used i think it's all gonna work out um all right so there there is a specific template and this is where i have to think about like how much do i want to refactor to start um how much is in this this template that we need to figure that out how much is it already using from something else i'm hoping a lot so let's go this is this is what we're working with this is the starting view um my hope and belief is that because we're working with a form set and because it has that management form i think that if you have a let's say we've added 15. i'm really concerned about the error handling like the actual addition of this new 15 is is not so problematic i think but what happens when there's a problem that's that's the release where this can get a little gnarly because does django re-render everything properly that's going to be the big deal and i think that it does i think the reason that it will do that is because the form set here when you are in a post request is that it's reading from the request post data so if you have a valid post that has all the management data that says i actually have 15 forms in here not just 10 then it's going to ignore this extra attribute and basically create 15 bound forms in the form set that's that's my belief and that's what's going to make this tenable if we had to do a bunch of extra manipulation in here this would really get painful i believe so what we need to do then is not so much spend our focus on the view which i think is good and then really look at this template stuff to start and as i said a lot of this is going to be some htmlx manipulation and then wiring some things together there so i probably want to see can we can we do what can we create a view here's a starting point let's make it so that we can take that last form element and add the htmx on there and with the htmx on there it can request this other data it's going to be a get request from a different view and we can make a very dumb version of this view that just returns like nothing related to forms it could be an h1 tag that just says hello world i don't care um and we just want to prove that we get the htm htmx that's hard for me to say that we get all of that stuff working correctly and then we can populate that partial with the actual data that we need to build i think that's probably the good plan to like build this up slowly so let's look at the course task for bulk form all right course task form bulk man that is a mouthful and let's see what's in here in fact i think we can get rid of the views just for a moment so it's not a very big um template we've got and the bulk of it so there's the button to add them here at the bottom that's that's cool there's already a little bit of oh that's interesting i'm already doing so there's some stuff in here that i didn't even realize that we have to pay attention to so i'm trying to excuse me i'm trying to make sense of this before before we get too far i don't want to like get sunk by uh this extra chunk of code so it looks like i'm doing some stuff and actually trying to filter out the number of filled forms but i don't know why that that's required i would think that django would just ignore those unfilled ones i don't know either i'm either current me is misunderstanding how form sets work or past me misunderstood how form sets work and either way it would check it out so um maybe what we can do is test before maybe before we go anywhere let's test out this code um to make sure it works as anticipate and then then we can possibly get rid of this code or the script block or or have to or we'll have to factor into what we do so let's fire up the server again come back to the page and um i think what i want to do is we'll refresh the page and so the way that i've written that that chunk of javascript is that it's looking for is there nothing in that form field and it's going to set the total forms based off of that value and then do a submit so it's dynamically modifying that management form already by changing the total forms and i think i don't know if that's needed hopefully the processing just figures that out um but we will see i i presume i put it in there for a reason so we're going to try and i'm just going to make this work differently by temporarily fudging the get element by id so it doesn't actually connect anything so i'm just going to put some junk in front of that and now if we refresh the page it's not actually going to have that submit button should just be a regular standard submit without any javascript involved so i'm going to try and say first and then we're going to say last and in this version of the things the total forms is still going to be 10. i don't know what it's gonna do i'm hoping that it will just ignore those others ah this is why okay well this is how the cookie crumbled i guess [Music] so i ran into a field validation problem is what clearly happened that the description is required so we're still going to need that chunk of that submission button and that's okay i think that's fine even if we add um you know five extra ones and somebody skips the third one but fills out the last you know 11 through 15 then um then that javascript is going to go over them and see the description is missing and still leave them undone so okay we'll we'll work with that and i don't even know that we have to really change that script tag all that much uh i think all of that code is still valid okay but good to understand that this is the these are some of the constraints that we're walking into all right um what else do we have here the next thing here is we've got here the everything in here is the actual form stuff and this is where we're going to probably need to extract this into a partial um because the html view that we'll build will need to be able to render this stuff again and fill in with different uh form values um that's going to be curious as how that's going to go because some of the structure is like here's form.course so it's using a course task form and has access to a course element already but it's building out as well it's using a name the html name so i'm not sure how we give it the like seated with the right numbers that's going to be interesting um because it's populating like the getting back to the form 0 description and all of that that is actually coming from some of these other pieces where's where's an example um where's description there it is okay so this is uh it's a generic field so there's actually there's a bunch so there's interesting complexity in here i guess this is what we're getting at is what i'm getting at so whatever we provide we have to provide a form that when we all the stuff is extracted into partial the form has to be smart enough to know what is my index supposed to be so that's going to be interesting to figure out okay the other thing that we need to do is the last form oh man this gets even even more interesting i am using a pretty generic field template that i've got excuse me and you can see that it's saying field is the description field in the form and there's some attributes that i'm passing into it and so we actually look at that so we can say forms and then field and so it's this special template just for this stuff but what i was hoping to do was actually render this stuff and render the htmx into this field into frankly probably this one of these inputs i don't know which one uh text area so that's actually quite difficult to do because what do i really need to pass in here i could make it so that a field had all sorts of extra attributes and maybe this is the way that i want to go so if we want to use for all the things that we'll need what what will we need well maybe we can sketch out what that will be so we're going to do an hx get and so there's going to be a value for that get so an hx get with a url and we need a trigger value and the trigger value is going to be something like in htmlx terms it's going to be something like once with uh with changed and then a delay of like one second or something like that and what that will do is is it will trigger the the get request but it'll only do it one time so the event will only be bound once and then it will not uh happen again um and it will happen after delay so there you go and then there's the hx target which is the where is the content gonna go but all this stuff is starting to add up like to quite a bit of complexity because that field is supposed to be generic and if i add in hx attributes like let's say um coming down to the form field let's imagine that that we did this with this generic form field and we go to this include and we say hx get and then we provide a url and we could do that and you know some url would go here the the problem with this approach is that this field is meant to be servicing a bunch of different types so do we put the hx get on text area or do we put it on input or do we put it on this other input and so to truly make it generic and work for all the stuff in the system i think i'd have to put it everywhere so that's that stinks frankly but it might just be the way to do this because this field include is the way that i'm keeping the entire site consistent whenever time whenever some of these fields are included so even though the complexity this it makes this particular template complex and and gnarly frankly but um it doesn't add the the uniformity that i need for the site otherwise i'm going to be adding kind of off by one templates that are similar to this stuff but not not quite the same and there's a lot of things that have been fixed in this one template like you can see field values and safe escaping and autofocus and there's just a bunch of things that have been incorporated this into this so well stinker that was that's a lot more than i anticipated so maybe that's that maybe that should be give me pause of maybe this isn't the right way to do it um perhaps i should be thinking of of other choices besides htmx because this is this chunk of markup is already pretty complicated and there's not great ways to feed that into a django include tags this is going to make what would be very linear or or could be very vertical in the markup language and readable would all become have to fit into this one long flat include line in the django template and that starts to be not so great i'm trying to think if there is a way around this so i know in some markup languages there's kind of a way to say and even in django in some places you can do something like and i don't think king glue does want it but we can pretend you can do something like end and then the tag and then what you can do is that anything in that you put in here would go inside of the the template that you're or the tag that you're trying to render and so there could be an outlet that says um hey i have an um hx block or something like that that could take any of that content i'm trying to remember if the template tag system in django allows for that what that would look like so let's go take a look because i don't i honestly just don't remember custom tags that enough so there are a variety of different template tags this is a filter uses the pipe that's not really what we're interested in so we'll keep going and i could be remembering jinja it's it's i've worked with so many template languages it's hard to keep them all straight so a simple tag is like a just a replacement so you call it and it pops in a string value it's not what we want and here's a custom tag that says taking a bunch of parameters and gives you the value here's an include tag so this is a way to do like a chunk of a partial chunk and maybe there's something an include tag might might be a way here or we could we could also consider making a totally custom tag just for this kind of work like an hx tag that's something to consider i think it would still we'd still have that nastiness of of having to modify the field tag but we'll think about that so that's what an inclusion tag does and let's keep going what else we have so then you get into some really advanced stuff with dealing with template tag parsers and dealing with the tokenizing and all sorts of stuff i don't think i'm just not seeing the things that i think we need well rats all right let's think about and include tag so what if the what if we did revisit this field that field template let's go back to that for a second what if we made a special tag that was an include tag that took a field element what else would it have to take though i think we'd be running into the same problems that's sorry i'm not not really putting a lot of all the full thoughts together here so at least try and string this together um so if an inclusion tag can can render a field and we could have something in our form down here and replace this form description with something like hx field and pass it form description as the form field to use that's we still run into the same problems that we had before where i would know now need to do hx get equal some url and hx trigger and pass in all these different parameters that would be in the same linear form we don't actually solve the problem with that which is too bad so what else could we do can we can't really like wrap i was trying to think if we could wrap this template with htmlx stuff i don't think that really works because uh it expects to be on the actual element that you're interacting with so even if you wrapped it it would go well actually maybe that there's an aspect of hdmx here that that might actually be to our advantage um let's bring up the docs again one of the things that htmx has and it was just pointed out to me by the author at some point is that stuff will go up to the parent i don't see if i can search for a parent in here so if you if you include um an hdmx thing and it requires some of these other attributes you can get those other attributes from a parent element so we can maybe do this in like modify the field minimally perhaps and wrap the rest of the stuff in attributes that we can add the pieces of information that we need um and that might work as a as i can include so what would that look like um well let me let me see if i can show you the other example of where hx is used um so we can get rid of that silly example that we have and we're going to search for hx in the stuff that we've got and i think what was what was pointed out to me by the author is like here we're here i've got something saying hx delete and there i believe there's an other there's a wrapping well no i left it in here in my dialogue with the author of this library uh who i talked to briefly on twitter so there's a twitter conversation for whatever that's worth um he pointed out or or the author pointed out i actually don't know if it's a guy or a girl um or anywhere in between and um the person pointed out that these attributes can be moved up to a parent element as i just said so as long as we have some kind of something in there like an hx get or something then if there's more information that seems to be missing like the target and some of these other attributes we could get that from a a wrapper a wrapper div that has that defined so what we can do perhaps is to say go back to this form and then modify could still we'll still need to modify the field template to include an hx somewhere so we could do something like um hx get like this is the text area so all of this stuff is we could do something like if hx get then we put in an hx get attribute with whatever the value of hx get was like um i think it doesn't have to be quoted yeah and then hx get so this that solves the problem of like being able to say get something and then the problem is like i don't want to complicate this form with a bunch of other things so this is where in this description stuff we could wrap well it's already and already has a div wrapper around it we could say here like add the extra stuff that we need so what's the hx trigger and i think that htmx will look at this parent and see okay here's all the other attributes that i need to have to define to to know what to do with this get request so i think that that could work and it seems like the least invasive way to go so i'm feeling feeling pretty good about that so let's try that this project is starting to be way more complicated than i anticipated but hey that's what happens and i'm also i'm not going to try and solve for all input scenarios right now i know that this particular one has an hx get requirement and it's on a text area so um it's not ideal it's not the universal solution this could totally bite me if i am trying to use this generically on fields in the future but i frankly don't see a lot of circumstances where i'm i'm going to always need this stuff and so i'm okay um leaving it as like this and we don't even know if this is going to work yet so it's a theory and we got to play test it out all right so let's try just getting the rendering working we're not actually going to connect it to anything right now any actual url we just want to see can this work and will htm x respond in the way that we anticipate so the first thing i want to do is we need to only include this on the last loop so django includes a special variable when you're inside a for for loop and the variable is called for loop and i always blank out on the attributes that are available for loop so django template tags and let's search for for loop here it is this table is very useful so on the template tag stocks this is the for loop stuff and this is what we want as a boolean that's if we're last for loop.last is when we want this different version of the include and we'll say well it already created the end if oh what we need else so we will need an else in here for all the other times and just to so that you can see it work in action let's drop an h1 tag in here that says oh well all right all i want to do is prove a little little baby steps especially since we're kind of moving into this unknown territory of what are we doing and i also have this form that we need to clear out okay all right so this proved that this last one is in fact handled differently great okay so the next thing we want to do is we've got i added this hx get and i think that might be the extent of what is required for the field template but we need to include that on this field right here so at the end we're going to say hx get and we'll say for now we'll just say i think we can give it a plain string hello slash hello like that okay so we're going to refresh and with any luck we'll inspect the element we'll go look at the field and see if it added the hx get attribute let's uh click in here and inspect and there it is hx get hello and i think that the text area will fire off that hx call if there is any change to it i think this default default behavior for text so we'll try this or maybe it's a focus loss there it is all right cool oh look at that that's fascinating it also put in a query string argument very interesting okay not what i anticipated but hey so but it proves that h htm x is working um there's no hello url so it failed uh unsurprisingly but it has the idea in mind so i think we now have enough to um to proceed now the question is how do we populate it with the url do we need to use like a can i use the url template tag in a width block let's go find out because if you look at this closely right now we've got a raw string in hx get and we need to change that to a url of whatever this htmlx partial rendering url is going to be and that has to be built by django using typically using the url template tag um we could inject it into the context from this view itself but that gets kind of messy especially when it comes down to rendering the partial again and we can't do the raw string so i think we need to figure out if we can use url with with statement there it is okay so you can assign it you can use the as keyword cool so our next step is to create this dummy view that has a little bit of content and let's let's get it as far as we want to put that after the [Music] what after the last form row so that's this row right here we're gonna have to give that probably have to give it an id um yeah there's gonna be little fiddly bits in here that we'll have to deal with but i am pleased that this this strategy does seem like it's going to work we still have to prove out that one thing that parent attributes can get can be the source of all the other information about where to do like triggers and targets and all this other stuff um but i have no reason to doubt the author that that that will happen so i think we can close the field stuff for now and we can go back to the courses views and then here here's where what's this going to be this is going to be a template view and well we can just use a regular view there's no reason to make it a class based view it's not going to be complicated um we'll need to do probably a lot of the same stuff that's that's already here um i think the previous task is only used by this bulk page so yeah let's not look i'm getting ahead of myself again apologies so what do we call this thing what have i called them in the past um they give it htm x in the name called it hx delete all right i'm using the hx prefix rather than something else so we'll say course what is this thing let's just be truly as descriptive as possible um get course task bulk hx that's that's pretty close and let's make make it happy here all right and so we need to return a response that is actually a template chunk so we're going to pass it the request we're going to pass it the the actual template thing that we want to build which we don't have yet so we'll say course task um well i'm going to try i'm going to use the one that's right above it there and then extend that this is a partial this is the extra stuff that we're going to be getting um to add to this and for the moment let's we don't need any particular context so we can put it like that and now we need to wire this up to the actual urls file and so that we can actually get that by name so here's the bulk view and we'll say uh this is we'll just continue to use the same pattern it's going to be partial so this is a url that no one's really going to see it's just going to be like a javascript url so i don't really care about the naming too too much and get bulk there and then we can say i want to reuse that same exact label course task bulk hx or i don't know that's too much task again let's use the same kind of convention as above so we've got task create bulk hx and that takes a uuid and that uuid corresponds to a course so now we can return to our bulk form and we can go to this last loop and we can say um url and we'll pass it courses and tap what i just call it task bulk hx task create bulk hx grief it's terrible bulk hx and give it the course uuid and we want to say as bulk create partial url yeah task created bolted bulk hx so this is going to the proper should do the proper url lookup and then now if we come down in here and go to hx get and replace it with put in bulk create partial url and refresh the page with any luck we did this all correctly and can revisit this and inspect the element and here we go now we've got this hx get with courses and then some uuid and tasks bulk partial cool i think that's a start um when no if we try and here let's actually try to see what happens because so it's now going to work work but what you'll see is that this should actually 500 because that template doesn't exist so we get an internal server error and i'm sure if we look at the response as django is rendering a response oh it's not actually it's not the reason i thought um there's a uuid on the view that i didn't pass in so let's return to the view and bulk so we want to come here and say uuid but that's still going to fail because we don't have this template that doesn't exist yet we can return to this and we're going to create a new file course task form bulk partial save that and say hello in the default i actually don't know what h tmx would do when if it just if it's going to replace it or this is where it's going to be interesting i'm not sure there probably is a default or maybe it'll complain that it doesn't know what to do with it um yeah we're about to find out refresh the page go to last item type some junk and tab over what happened well didn't appear like anything happened oh there it is okay so it said hello but we didn't do anything with it there was no attribute there so it i guess it just said whatever and moved on but it did do the proper request we actually got a proper response and and so now now i think it's up to us to add the extra attributes that are going to make this tenable so where oh okay so now we can go back we can return back to the bulk form that we were just on we can go to the partial area where we just created that and here's where i'm gonna the way i'm gonna do this is by wrapping this div with a span i'm gonna use a span because a span does not follow in the um the block or what's it called and the block modeling for css stuff a span span is a dimensionless thing um in html and so it gets it's a good container that i'm not worried about it affecting the layout so just a place to put attributes in my mind so we've got our span and now we want to say now we want to go back to the hdmx documentation and start adding the different attributes that we want in here and so let's start by putting in a target and telling it what to do and we'll do the most extreme thing first of saying like let's just replace the entire form set it's not really what we want to do but we just want to see if it's actually going to work so the thing we want is hx target and we can give the entire form an id of replace me and then in hx target we'll say percent or pound sign replace me not percent so that should be the right target and then the swap behavior that we want is outer html okay this is just proving trying to prove that parent behavior works as we expect i'm going to come to here and i'm going to add some more stuff and didn't seem to do what i wanted i thought it was going to do why we're working from the same form okay yeah i think it's because we're working from the same form so well rats so definitely do the get request why did it not go let's see if we spelled everything correctly because we've got hx post we've got we don't have trigger but i don't think that matters there's a default trigger and default triggers focus on the text area because the trick we know the trigger is working because hdmx is doing something it's it's trying to it issues this request and we've got hx target which is i said id is replace me which i spelled correctly and here i also spelled it correctly and then i said swap with the outer html well shoot all right let's try let's not let's take the field template stuff out of the equation let's see if we can just prove that this kind of parent behavior stuff that i suspect is supposed to be working is actually in fact working so we're going to put that in here with a div and this will say replace me and this will be the parent that we're trying to represent and we'll say id is equal to um really replace and then within this we'll have the anchor tag of um i guess it doesn't need to be an anchor but whatever hx get actually let's move this up a little bit so we can reuse that url hx get the bulk create partial url and the thing that we want to target is the really replace i want to make sure that i have a working understanding of what this is supposed to do because it seemed like what what we tried should have worked um so this first version i'm putting all of the attributes inside of the single anchor tag so that it should takes out the the whole does the parent inherit stuff part of this completely the default is the default trigger is click so we're going to say click me and then we'll say div this isn't going to look pretty but it should be functional so here's the if this is working as i anticipate by clicking this this whole chunk should be replaced with hello and it was all right so time to re time to move some things around and see where where is our my understanding breaking down or where am i introducing a bug somewhere because i could be so we have really replaced and really replaces the target so let's take this stuff and let's move these couple of target attributes up so we're just going to leave the get with the actual anchor tag and move target and swap to the parent yeah i'm hoping that this works reload the page back to replace me if i click this it still replaces okay so what if i say instead of really replace let's replace the whole flex row by switching it to replace me which is what we're trying to do i click this i want i'm expecting this whole road to go away and it didn't why so we hit the problem and we can trigger this multiple times so here's the response why did it not replace the form all right let's let's take the only other thing i can think of is just like it's apparent above this stuff but that doesn't seem really super sensible to me so we could try wrapping it in another div but like i don't really see the point so so another div and we'll say another and we can put in that div tag and change it to another div but i i suspect it will get rid of that all that stuff so yeah we'll keep walking it up until i see what's going on okay could definitely replace all of that stuff that's good let's move so i'm all i'm going to do is we know that this chunk of code does actual replacement and this is the parent of this which is the parent of the actual thing we're clicking so it's gone up two levels so in theory i know what it did it did replace it we probably just didn't see it maybe because remember this is in a loop so this replacement id is now duplicated for every form all right so okay that's where i went wrong so let's give this a for loop counter i think we have to do counter zero or zero if we want to match that particular form right now we can use counter zero it doesn't really probably doesn't really matter but okay so now we have a replacement with a with a index attached to it so each one should be unique maybe that was the problem is that ids in html are supposed to be unique and we were giving all 10 forms the same id so hdmx either picked the first one and i didn't notice or it decided nope i'm actually not going to do any of them either is reasonable so this time we're going to go to another div and we're going to change it to replace me and we're going to use the same logic up above so for loop dot counter zero all right now i have a bit more confidence that this thing is going to actually replace what we're hoping to replace oops uh what what page was it okay i definitely got rid of something something happened but i don't i don't know exactly what it cleared out clearly it got rid of something in this equation oh you know what it is these divs well no that should be for the whole row what happened okay well at least we're on the right track of we just need to put in the right id and it should do the right thing we'll keep using this synthetic example until we get this right and then we'll try and push it down into the field template to make sure that that's doing the right thing let's close this for a minute we don't actually need this we just want let's get some more real estate so we actually see what we're doing if we totally refresh this page and get okay we want to see a container all right here's replace me 9. interestingly this thing that we have right here is not including the counter the number or the checkbox that's unexpected i would figure that would be for the whole row that's very surprising so it could be that my markup is also quietly incorrect here and these other elements are just happen to be setting on this page appropriate appropriately because i have a div with the width of 3 6 and there's another div below it with the width of 2 6 which is the counter and there's one last one that's the check box of 1 6 and this this div should go with the div where we added the id and it does so how does how is this logic working that this thing why is this stuff sitting outside i must have messed this up when i'm doing this last logic because all the rest of the like you can see that's right all right fine fine fine um what's going on oh here it is i have two closing divs okay okay inspect this again now it's got everything now if we click this the whole thing should go away yeah whole thing went away was replaced with hello cool so now we want to say instead of something silly like replace me let's switch this to form row that's much more reasonable to say and here it would be form row we'll keep taking baby steps to make sure because apparently this is trickier to get right than i anticipated um go on good okay so we want to observe the same behavior now not with a synthetic example but with the form field example that we had earlier so i think if we did if i did this right my belief is that i should be able to change this with form row dash for loop counter zero like that and now the field replace should also work yep awesome okay but this isn't really what we're going for we're actually going for append to the end and there there is a different target attribute that we can use so if we come back to the docs here and look at targets so we can see that our target is going to be this whole row that's where we're coming from in fact i think we're now in a position where we can comfortably get rid of this div that we added to make sure that this is working which was this chunk right here so we're we're back to this what what it should look like and when we get rid of this focus it it actually it didn't look like it but it deleted one in order and actually we can prove that so we can go should be second to last and then we fill in this and lose focus and you can see second to last is there as the last one now so we don't want to replace the element we want that the new chunk to be rendered after the element and one of those target options is what we need to switch it to to do that and i don't know it's it's going to be append the contents after the target in the target's parent element probably this one after end i don't know we'll play with it make sure it looks right make sure that the markup is where we expected to be but i think it's going to be this after end come back here refresh um we will now if i type in this is last this shouldn't go away we got hello here and let's inspect this where did it get put where we wanted to be if it the answer should be after this thing should have been put after the form um and come on hello it did so it's just it doesn't look like it or doesn't seem to fit very well but it is exactly where i want it to be like so imagine you know this partial is going to be rendering say five of these forms so it'll be 10 11 12 30 14. and so these five rows will be here where the hello is cool so what is next then what is next is um replacing that partial with the actual form so let's refactor the bulk page where we have the form and put that in a its own little partial we're going to take everything that's in here and we might there's there's probably some we probably need to work look through this template and see like there's definitely form is used there's also course so this partial is going to require the course as well um these are pieces of data that we'll make to have to make sure to pass in and you don't technically have to do that django will try and take the context that's available around it and just assumes that that's what you want but i'd rather be explicit to show that this is what the include requires and so i'm looking through this we've got it's using it's definitely using the form it's using the course i'm just looking trying to look at the rest of this template quickly and see if i can see anything else there's also um is grade levels coming from the template ah shoot all right let's go back to the view and see what else is in the context so there's more stuff in this than whoops then is desirable but you can't really avoid that i think we're going to need we don't need form set we need form and but we do need course and we do need grade level that is curious oh oh oh it's great levels okay i was really confused by this filter for a moment but i see well shoot okay that's what it needs that's what it needs so let's put some notes here hey hester welcome um i am working on a bulk create page for this this homeschool app that i'm building uh it's a page where a homeschool educator can create a bunch of tasks at once and there is a a default set here of 10 forms that are included to create different 10 different tasks if they so choose but i had a customer request that i make this page dynamic so trying to find it well they were actually requesting for an add button like giving more tasks but i want to make this the user experience really slick so that when they're in this last box and typing um that it just automatically adds more forms as they as they need them so that they can submit a whole bunch of forms at once if they want so that's that's what i'm working on so we the new view is going to need so we have to get a course for the context we have to get the form for the context and we have to get the school year's grade levels all of those things go into this chunk of stuff that is rendering this row of data for this bulk form in fact that's probably the best name for it bulk form um oh man there's also the this counter that's going to be coming into play so we're going to have to add in the for loop counter so we're going to need a form number that's an interesting question hester do you have to learn html css before you learn django to a degree probably i mean there there's plenty of things you can do with django and you could make i'll caveat that so i don't think you have to learn css css can make a website pretty and adds all the styling and stuff that's not a strict requirement before learning django um at minimum though if you want to make a page that a browser can understand then you probably need to learn the very basics of html and you know you need to learn about html tags the head tag the body tag and like paragraphs and little bits like that that would be enough to slap together some presentation of data um if you want to make it look nice like if it's more than just some internal website that you're building for a company and you want it to look nice then you probably then would move into learning some css to learn more django to be better at chango but um i don't think those are strictly required or at least the css portions not so there you go there's my thoughts on that all right so i also said we needed the partial we'll need a form number i guess which is going to be which i knew was going to be needed anyway because if we're for rendering these forms oh no no i know um this was coming from a form set so actually maybe we don't need a form number explicitly maybe we need to get it out of the form object so can we extract that number from the form set form it might have access to the number somewhere in there that that we can use that would simplify the amount of data we could do it with i can make a dumb version that just takes the for four loop counter but that's going to have some other failures excuse me so i think what i want to do now when i get that frog out of my throat is what i want to do and then we'll we'll do the the actual html extraction okay so let's take this chunk of div this flex box and let's extract it out terribly sorry i'm got some water and everything it's just not going away okay feeling better so we need the course task i don't want to confuse this because there's already the form bulk here and so i don't want to create if i if i just reverse that name and call it the bulk form which is kind of what it is that would be mega confusing of what is this and then we also have this partial which is the set of forms so we're running out of names so this is the the name that i would want to use is the course task bulk form that would be the name that i would desire but the view uses that for the whole collection the whole page um so how else could i modify i could say this single which seems really weird when you're saying bulk course task bulk single form i don't know i'm not wild about that name but i'm running out of brain cells i guess to figure out better names so let's um let's go back to that template the bulk template let's go to the area where we were just at and let's take all of this tag and for now let's go back into the the thing we just created the bulk single form and paste it all in okay so got we have a new chunk of code and it's still it's it's expecting stuff that like if we don't use this just right right now it will blow up and the reason that it'll blow up is it's gonna blow up if it's the if the for loop if not if it's not running inside the context of a for loop it's not gonna like that yeah that's going to be a problem at some other point so let's do this we'll come back to this bulk page and now we should be able to go to the include the same area this form set and what i'm going to do is i'm going to switch it with an include and we'll say courses and then oh gosh what did i just call it course task bulk single form or did i say bulk form single i don't know um and with course with form equal form again this is isn't strictly necessary but this is kind of telling me that this is what this partial template requires um course equal course and grade levels equal grade levels django doesn't strictly require this but it i think it will be helpful and then there's that for loop problem that we're going to have and for the moment what i'm going to do is comment out all of this stuff and see if we got it right with the include so in theory everything should render exactly the same because all we did was we moved a chunk of template code from one template file to another and we should still be able to come to the end and do a change and trigger a render and now we've got this okay so here's where we can now take this same line and we can put that in the partial where we've got this hello now none of this form and course and grade levels those don't exist so i actually don't know if if i think i think django will just i actually don't know what i'll do we'll see let's find out well refresh and let's bring up the network because i suspect we're either going to get a 500 or we're going to get a weird looking result we got a we got a 200 and here's the response it's some form stuff it dropped one in well it's actually kind of cool this is what we're trying to do right so we can inspect this we can see what's in here it yeah it's haven't it has a lot of blanks where i would expect there to be blanks so it's a form row but you can see there's no number here so it didn't know what did it not know right off the bat um let's go to the single form and take a look so it had no idea what the for loop counter was it doesn't know it's in a for loop and i guess the for loop does not propagate down to the include i'm not too shocked by that also because there's no for loop this for loop that last is undoubtedly not working so what we really need is to loop over some things and we can try and create multiple of them and then then for loop.last should work in that context because it will actually be part of a loop so let's go back to the view for a moment and let's just put something into the context let's move the context out from being this empty dictionary and we're going to change it to go here and we're going to put in a list it doesn't really matter what for the moment i'll say forms because that might be the things that we want to actually pass in and i'm just going to give it some numbers one two three because we're not actually going to care about anything that is actually coming up we just want something to loop over so now i can in this partial i can say for well um so it doesn't conflict and look at stuff that doesn't have because that's going to be a number that will try to attribute axis on which isn't going to make sense before fake form in forms this is just giving us something to loop over and now we can put that include okay we can return to this page and refresh come down to the bottom and now if all goes according to plan once we change this and lose focus here then it should populate boom it added three more that is curious i wonder if that's so there's some side effects to this that maybe i didn't anticipate is we're at the bottom so somebody's going to type type type type they're going to get to the bottom and then type here and the page is going to jump on them that's from a user experience that's not great i don't know that there's how much we can control about that though it would be really disorienting so i was thinking of having actually let's let's put in what i was thinking of doing originally so there's originally 10 forms on this page and i was thinking of adding five more so now we're coming down to coming down to the bottom and we type in something and do a refresh look at that it almost completely like if i had done even one more i think people would have been pretty upset because it is uh it's populated so many things it almost goes off the screen like if it had gone just a little bit more and and you'd you were typing and and frankly like right now it's working on change but i was i was thinking of just doing this on um like once they're they were once the user was typing actually maybe i can go ahead and program that in and should just show it it probably would make a better demonstration let's go back to that single form and so we didn't put a trigger in here and so the trigger on a text area is when it loses focus so when you type and you go somewhere else then it fires so what i really want as the trigger is um to use hx trigger and i want it to be a one-time thing so that you can say you can say once let's go to back to triggers um so i want once and i want it to be when it's changed that's a good question so the reason i'm i only want it i only want to add more form elements once uh it doesn't matter if the user makes a typo like they'll be able to save that later but i want to give them more boxes to say like oh you're adding something here and um that way they automatically will be able to add more so it's it's not really concerned with like the errors that they might be making and the ones will should guard against like they they should be able to after they've typed in whatever if they want to change it that's that's fine it won't fire anymore that's what the wants should be doing so we want to say once changed and then delay and one second i think is the syntax for all this stuff so this is this is the experience that i really wanted to have is is this trigger right here so let's return back to this page refresh and come to the bottom and so now i'm going to type type type type type type type type stop well didn't uh didn't do what i thought i was gonna do but still working on focus so maybe maybe i don't understand what the changed trigger is um triggers where are the triggers this is the let's go to the trigger attribute see if there's other stuff i thought change would be just stuff you typed but apparently that's not what it actually is maybe we want key up yeah let's try that so instead of change let's try key up once key up changed one second so that gets slightly more aggressive but again if it's only a one-time thing then it it's probably fine so type type type type type hmm still not what i anticipated still only like after it's losing mouse focus [Music] what am i getting wrong [Music] today okay changed is definitely the thing we want and i definitely won't don't want it to happen more than once so um that's that's that's that definitely is the important part so even if it's just a okay let's assume that it will only be after focus that's probably okay i was trying to get something a little bit slicker but if somebody tabs and then it shows them a new one when they tab out of or or click out of that to yeah there are some downsides to that i was hoping to get this because let's let's look at the page the only thing that is required for some of these is this um description and then this number these are these aren't filled in with data yet but they will be so these will be filled in with a number and there will be a check box here in in the final version and they shouldn't have to do anything for those necessarily it's like a default value so they may get here and they'll be like this is my last task i'm finally done and they don't they just want to click the button and what i don't want to happen is like they come out and scroll down and and this box still had focus and then they click and then have um some ajax call happen and a bunch of forms appear right before they click submit and see how stuff happened that that seems like it could be very jarring if it did happen and it would be like a race condition which is why i was hoping that it would um trigger on the key up so it's not like waiting for them to lose focus on the text area it's more like they're just done typing stuff and they're like reaching for their mouse and in that process or reaching for their trackpad or whatever it is so that's why i'm i'm a little disappointed that this is not this doesn't seem to be what i expected so how about if i take out changed and just have key up but what i don't get is like this is key up changed and they're together here and i don't i don't feel like i see a full list of events uh oh well okay so we've got um i've got this version with just key up it's not changed anymore yeah i that was actually what the customer suggested to me was having an add button but i didn't want to have to then have to have this intervention process so i'm trying to be slicker than even what the customer was asking for and and i'm hoping to offer a really smooth elegant experience but you know if i can't deliver it maybe the more reasonable thing is to have the button and say like give me five more and there are definitely some downsides that i'm saying in this approach as i'm doing it like it doesn't these things are not maybe there's needs to be a css transition in maybe i need to do one at a time um i i might actually yeah i definitely don't want to give them like how many more do you want because i don't want to have a bunch of numbers and things that they have to insert and like do they if it's something that's meant to be an optional feature and i think that would my personal taste is is that's not not my desire there but i i respect that you you would like that design that's just not what i'm gonna go for um well shoot um htmx is not doing what i think it's supposed to do but that's probably me [Music] here's the there's the reference and let's see if we can find key up nope this brings us back to that page we're just on key up is only mentioned here in like two places i wonder if this is like coming from javascript itself or the browser itself browser key up event yeah there's probably some like official definition of events that the browser can fire maybe that's why it's not defined i'm just shocked that that this trigger is not doesn't seem to be doing what i expect it would do like there's if this is the event name which clearly maps to the documentation that the person has here key up and we're saying once i mean i mean i can take out key the once part let's see what happens with that when i do that so now we're coming back to the last one and there's a delay of one second so blah blah blah but again it wasn't until i left the text area now there this is a new library so it's maybe it's possible or either well browser text area key up does it react to key up is the question what is this person saying they're saying use well what's the question let's just poke at it let's see if a key down works instead because it seems it's seeming like text area is not respecting k up or html x is not respecting key up the key up event we'll come to last one type some stuff it's not until i tab out and lose focus that it actually does anything i always change it one more time and then i'll give up on this for now and maybe go file an issue or maybe there's a known issue although i'm doing this on a span so maybe that's the problem the i bet that's the problem the trigger yeah i bet the trigger is not being applied because it needs to be on the field so this is one of the areas where the parent attribute it's not reading from the parent attribute is my bet so it is reading that the hx swap part part it is reading the target part but i bet that the trigger itself needs to be on the field so let's try moving it just for the moment and we're going to come down and put in so let's go return to that field template and we're going to hack it in for a minute there's this hx get and the only thing that's using it on the whole site right now is this one area where i'm using hx get in this include so it's safe for me to hard code in the hx trigger here with the value that i want which as i said initially i want it to be once and i'm going to try changed with a delay of one second and then let's comment this out and see how this goes this is a this gets much closer to now this is going to be on the text area itself presumably yeah once change delay one second well that didn't work at all curious so i went all right let's go and put in once key up changed or delay one second because that was the other example wasn't it if well they don't have once but they have key up change delay one second let's try that and come back over here refresh that page so one second has definitely passed and oh man that's not good that's like a major regression hx trigger once key up changed delay one second can we get any kind of trigger at all let's take out the once oh there it goes but here's the problem with this now if i do this if i come back in and add more boom it just added another five that's bad so it's really critical that this once aspect work hmm because i'm kind of in a pickle if it doesn't and it seemed like when i had once on there it didn't work at all it went from working every time i changed something to no working not working let's put it back in oh there's a htmx syntax error minified so i can't tell so i guess it doesn't like once key up changed what if i take out well oh well hold on is once a new feature there's a release history somewhere on this project um come on i was just looking at it earlier today where did it go there it is announcements so i'm on html 1.1 here's 1.2 i'm not going to look through all of those but i i don't know when once was added okay can't see anything there let's go look at the actual project once well there's none on this first page once on the second page once nope well phooey let's um let's break it down so we can do we can take out all the stuff in trigger and change it to click and refresh the page and now this should fire as soon as we click on it and it did i guess but it put it did it also move the thing that was weird okay not going to think too hard about that so click works no console error let's switch it to changed because that is supposed to be the default for text area refresh and type some stuff lose focus didn't work why there's a note about change versus changed but the examples on the trigger section so show changed as in past tensed tense click click click change is the name of the event changed is the name of the modifier oh okay maybe i'm not reading the documentation right hx hxtrigger tells you what triggers the ajax request a trigger value can be one of the following the event name aha all right so i think i'm com combining so changed is not right changed it should be change that's the event we come back what seemed like it wasn't working this should work whenever this changes like so there we go it rendered one two three four five forms as soon as i lost focus the change happened but right now it's broken because if i do it again it's going to render another five forms there's so there's now ten forms below this one two three four five six seven eight nine ten and then our area up there so we definitely need once as the modifier change once i don't think that the modifier order matters this is my read of the documentation but that's what we're going with so asdf tab got five more we'll add in another one asdf tab and it still sticks with five so we definitely want that all right but as i said i'd rather do it on a key up so i think i want maybe i don't want key up changed i just want like any key up with a delay and i only want it to happen once so let's change it from change to key up because that's the different event we'll do it once and then we'll do delay of one second so type stop boom bunch of stuff five new field five new forms type stop no more okay good um we're gonna need probably a css transition to bring in new forms gracefully fade them in or something because it looked look pretty trashy i think i also want to dramatically reduce the number of forms that come back probably just down to one the other thing i want to do is i put the trigger in the field but now i'm not so convinced like we had the wrong stuff in the trigger above so i'm not convinced that we need to put it here so let's take this stuff for a moment and put it try and put it back in the parent now that i know this is the configuration that i know it works somewhere so let's put it like this for the moment so i know that works and i've removed it and saved removed it from the field and moved it up the parent let's make sure it still works stop well nope now now it had to be a tab so the trigger has to be on the actual text area so put it back there remove it from here and just for one last sanity check make sure this is the right observable behavior last one there's no change so there's no key up type the type boom yep okay all right i think that's illuminating so we're going to need um i need to pass in an hx trigger to the field that's unavoidable let's come down the end we'll say hxtrigger is equal to a string and we want it to be key up once the delay of one second and delete this comment and i'm going to duplicate this line and switch hx get to trigger and say trigger and trigger with any luck i got this part right and we can come back to this page come to the bottom try it again did i save everything everything's saved um type some stuff stop well shoot oh oh this is like an old old form okay type some stuff it loads great okay wow that was uh significantly harder than i wanted it to be we didn't even get to any of like the population of the real form data and going for 2 hours and 15 minutes so this is probably we're going to stop we have at least uh the kernel of it seems to work of what needs to go in here and the rest of it is like data population and filling in with the real values and i mean unit tests and like access control stuff and a bunch of things that probably need to go in there although it's just an empty form so the access control like i'm gonna think about this one one thing before we get too far like it does it really need what we're really doing is some server-side rendering of a template that we're dropping in to the client rather than doing client-side rendering in the browser and what really goes in here well no it does need it does need the right access control because we do need to populate the form with some hidden fields like the course that's you can't can't get around that so yeah that's just the reality and if if this became a big problem performance wise which i i don't imagine enough usage in the any inter any time frame of this really mattering then i could move it to client-side rendering so everything that was put here like i could i could probably render um like one kind of shadow form one form that stays hidden and then have some javascript that could clone that form and replace the fields that need to be replaced so replace the form-number dash field name like description and that would all work it would just mean that i'd be doing more javascript rather than html so i think i'm okay with not doing that for now so in the end we get this modification to the field to allow for this hx get to be set and the trigger apparently has to be on the actual element um i wonder if that's by design or not that'd be interesting i might be able to file a bug there i'm not sure maybe it's by design don't know um and then uh getting back to the actual um well not this form where were we we were we're on the single form yeah so we've got the for loop and then we spent basically all of our time focusing on just getting this one little thing right but it's a critical thing it's the thing that actually does the swapping the other part that i want to probably change is right now it's doing five forms and i kind of feel like that was way too much because it was very jarring let's try it with two to see what it looks like just kind of trying to polish some of the what i want the experience to feel like yeah so the jump there was no good like there so there needs to be um ideally like a fade in transition so there's probably some css transition work that needs to happen there's there is documentation in htmlx about there are certain uh css classes that are or i'm sorry tag classes that are added to an attribute while hdmx is doing its job and so it talks in the documentation talks about what you want to do during css transitions and it seems like it's actually not not super hard um so it does a swap it puts in stuff later and then there's a there's two kind of a two-phase approach to this and it will add in the attributes and the attributes will be like one of these attributes will be a kind of a fade-in thing that we can do with the transition because i think what that's going to solve in this page is people are going to be pretty confused if let's say they're on the bottom of the page like even when i scrolled all the way to the bottom i see this stuff and i type in a little bit and it pops out and boom where did my button go i suddenly have two more forms and yeah it just feels kind of jarring and strange so i think i think there's probably a couple things that we can do to change that we can go to the bulk template that renders all this stuff and the last thing on here that's before the add button is this row so if we put in some bottom or top margin don't put it in there yeah we put in some top margin like uh mt 16 something like that now if we refresh this there's going to be more of a gap here so it's kind of this i'm trying to design for this this scenario where someone is is viewing this page and they can see the bottom and it seems like there's a gap so essentially what i'm trying to do is sneak in enough of a feeling that if i add well how's this going to work one of those it's still going to do the same effect isn't it it's going to just jump um i don't know if we can avoid that jump so much and i don't know that margin is going to help okay my brain sort of fried though um so we're going to stop here and um i will i'll come back to this and we'll see what we can do with some animations to make that look slick populated with data write the test make sure the whole thing works and that's going to be what's next so appreciate you joining in um hopefully you learned something you saw that that uh anytime you want to do dynamic stuff it gets pretty challenging um and and part of that is my own learning part of it's using a new library that maybe not all the corner cases are worked out yet you know it's probably worth me filing some bugs or at least asking some questions online and uh yeah but it's been an interesting experience nonetheless hopefully you enjoyed some of that and uh i will see you next time take care
Info
Channel: Matt Layman
Views: 444
Rating: 5 out of 5
Keywords: twitch, Python, Django, SaaS, htmx
Id: NYXB5wLheSI
Channel Id: undefined
Length: 136min 50sec (8210 seconds)
Published: Thu Apr 08 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.