fpdcc / ccfp-asset-dashboard

CCFP Asset Dashboard
0 stars 1 forks source link

Phase and funding forms on one page #156

Closed smcalilly closed 12 months ago

smcalilly commented 1 year ago

@xmedr is going to wireframe this so we can share with clients and get feedback, then we'll implement this.

smcalilly commented 1 year ago

@xmedr when wireframing, be sure to allow one or more funding sources to be added.

xmedr commented 1 year ago

@smcalilly Ah heard, so the potential to add more than one funding source at a time, gotcha.

xmedr commented 1 year ago

@smcalilly Here's a first draft

The note next to "Add another source" just says that clicking that could add another row to allow for multiple funding sources to be added at once.

image

smcalilly commented 1 year ago

@xmedr that looks nice. i added a comment on the moqup.

one thing to think about: how would the form submission work from a code point of view, specifically the backend view? the html form is setup to submit a post request to the phase view. adding another "save funding" button would require a new endpoint. submitting two separate forms on one html page is kind of a confusing pattern.

with that in mind, would it be possible to combine the two forms so they're submitted to the same endpoint? this would let us simply the UI and only have one "save" button. django inline forms kind of solve this. here's an example (with a rough ui): https://medium.com/@adandan01/django-inline-formsets-example-mybook-420cc4b6225d they simplify the form submission with one button.

smcalilly commented 1 year ago

submitting two separate forms on one html page is kind of a confusing pattern.

in other words:

clicking "save phase" sends a post request to the projects/phases/edit/<int:pk>/ url. clicking "save funding" sends a post request to the projects/phases/<int:pk>/funding/update/. it would be nice to consolidate those to a single url since they're on the same page.

just something to keep in mind. this could get complicated but maybe i'm overthinking it?

also, we might need some javascript to render the the phase funding forms as a user clicks "add another source". which adds to the complexity.

xmedr commented 1 year ago

@smcalilly Got a version 2 up. Notable changes are that the button at the top right changed to "Save All Changes" from "Save Phase", and the add funding box got merged with the funding list box. Also responded to your comment about the edit button

image

So with one "save all" button, I'm hoping that this starts to get us towards having just one url for the update. And it looks like the article you sent has an example of them using some javascript to add a new row, so maybe we can borrow from that when the time comes.

xmedr commented 1 year ago

@smcalilly I've got a couple ideas I wanted to get some feedback on about how we can get those multiple FundingStreamForms to submit.

1) Using Javascript to submit separate forms

Reading through this SO answer, maybe we could render each FundingStreamForm as a separate <form> element, and add a JS onlick() to the Save All Changes button that takes every form on the page and submits them as individual forms. The answer even talks about using that JS to allow the user to make as many forms as they want.

This feels like an okay approach so far, but I haven't tried this out yet.

2) Grouping form sets through unique names

This was my initial thought, but it's more convoluted and I'm not sure it would work. Like we talked about, within the PhaseForm, we can have a funding_stream field containing the FundingStreamForm, and use a loop in the template to make a few funding forms. (This example doesn't consider dynamically setting the number of forms, so for simplicity's sake we'll say 3 instances.)

If it's possible, we might be able to make these forms in such a way that each input's name can have a suffix with a number. Something like name="{{field.name}}_{{i}}" equating to year_0, year_1, and year_2

 {% for i in range %}  # let's say range goes from 0 to 2 for three instances
   <div class="row">
   {% for field in form.funding_streams %}
     <div class="col-md-2">
       <input name="{{field.name}}_{{i}}" type=(field-type-accessor) value=(field-value-accessor) .... />
     </div>
   {% endfor %}
   </div>
 {% endfor %}

Then in the view, we might be able to use the suffix numbers for each field to both group submitted fields into FundingStreamForms and instantiate as many of those forms as needed.

An issue with this are that I haven't yet been able to successfully recreate the input with all it's necessary attributes.

smcalilly commented 1 year ago

@xmedr these are some good ideas - thanks for sharing.

Yeah we can definitely do all of this in javascript. I was trying to keep things in django form-land but you're right that we could get away with submitting them via an api.

With number two, you might could render those inputs with javascript rather than the Django templating language. And then you can capture the entire form input in the PhaseUpdateView, including the inputs you rendered in javascript. So you'd basically use the FundingStreamForm in the view only to capture/validate the data.

One thing you'll need to consider either way — if the update view has any existing funding streams, you'll need to serve those up as inputs in the django template. So with either approach, you'll have to render in the template any instances of the FundingStreamForm (which are hydrated with the funding stream's data so you'll need the instance's id/pk), plus be able to add new inputs with javascript.

So I guess either way you'll need to generate the form inputs in javascript, and the question is whether to submit them via api (option 1) or with the phase form (option 2).

smcalilly commented 1 year ago

@xmedr thinking more about your javascript proposal, if you went that route, it would probably be best to submit the form after each funding stream is "added" (after a click event that submits the payload to the api), rather than submitting them all at once whenever the user clicks the main "save phase" button.

have you had more time to think about either of the options? i'm wondering what you're leaning towards.

xmedr commented 1 year ago

@smcalilly hm, i was leaning towards exploring the javascript focused option. and i might absolutely be misunderstanding, but would this essentially bring us back to filling out the form and clicking something other than the "save phase" button (so a button that's just for funding submission) to submit funding streams one by one, as opposed to making a few at a time and saving everything together?

because if that's the case, then i imagine we don't need to worry about the forms being sent to the PhaseForm's funding_streams list, and we can instead just instantiate FundingStreamForms in the PhaseUpdateView each time those single forms get submitted, right? let me know if that made sense haha, but that would be a lot easier than what we're trying.

also i was thinking, as long as we're allowing for preexisting funding streams to always appear as editable fields, how would we update/delete them? is there something about a hydrated django form that allows you to reference the primary key for the object that it comes from? Edit: i was able to just add the form's fundingstream id to the context and added that to the delete button, so now those can be deleted individually at least

xmedr commented 1 year ago

@smcalilly and on an simpler note, thankfully getting existing funding streams into editable fields and also getting js to add more rows to the dom for new sources wasn't difficult at all!

add_sources

xmedr commented 1 year ago

I'll be picking this back up!

@jim-z Just some questions in regards to you mentioning alerting users when they haven't filled out some fields on the phase edit page. Were you thinking:

jim-z commented 1 year ago

If it's an easy add, I think just a note informing users that they haven't added funding sources when navigating away would suffice. There are instances when phases are added without funding secured/known so wouldn't want to make it mandatory.