Correct way to implement a cancel button w/ UpdateView+ModelForm?
See original GitHub issueJust wanted to run this by you and get your thoughts…
If you’re using ModelForms and UpdateView, you’re letting Django take care of the form layout, tweaking some setting perhaps via Crispy, and then letting Crispy render it.
In these types of views, you often want to have a Cancel button on your form:
If you Google around, end users of Crispy don’t seem to have a consistent idea of how to accomplish this. ** Some people suggest appending raw HTML via Crispy’s helper object – not a clean approach ** Some people suggest just using Crispy to render the fields, then wrap your own form in HTML – not clean either, since now you’ve got to maintain code in two places ** Some people suggest putting a button in which has onclick=“history.go(-1)” – go back a page in the browser history. The history(-1) approach is bad if you submit with bad data, which posts and comes back invalid, and then try to cancel – in this case, going back one page takes you back to the form you submitted with invalid data.
(As an aside, Django is supposed to be Javascript-agnostic, meaning that if you’ve got to resort to DOM manipulation via Javascript to accomplish something this basic, you’re probably doing something wrong.)
I had an idea - perhaps you could add another Submit button, this time labeled “Cancel”, and style it accordingly.
basically, taking this:
self.helper.add_input(Submit('submit', 'Create Project'))
and making it this:
self.helper.add_input(Submit('submit', 'Create Project'))
self.helper.add_input(Submit('cancel', 'Cancel', css_class='btn-default'))
(The styling on the Cancel button was supposed to give me a basic black button as appears in my picture above.)
Since these are both form submits which do a post back to the view, your view code would look something like this.
def form_valid(self, form):
if 'cancel' in self.request.POST:
return HttpResponseRedirect(self.get_success_url())
return super(Project_UpdateView, self).form_valid(form)
Basically, seeing if ‘cancel’ is in the POST dictionary and redirecting accordingly, otherwise following the normal path. It ends up functioning, but I noticed that I had very little control over the styling of that new Cancel button. If I styled it “btn-danger” (i.e. Red button), that worked. Otherwise, it always seemed to end up Blue like the other button.
So I looked into the Submit class within Crispy and found this:
input_type = 'submit'
field_classes = 'submit submitButton' if TEMPLATE_PACK == 'uni_form' else 'btn btn-primary'
What this means is that if you’re using bootstrap it’s always going to get styled the same way (‘btn-primary’, i.e. Blue button). Due to how bootstrap works, the Red danger button overrides this style, but things like Default button don’t.
My solution:
create a new SubmitButton class which removes the “btn-primary” styling.
from django.conf import settings TEMPLATE_PACK = getattr(settings, ‘CRISPY_TEMPLATE_PACK’, ‘bootstrap’) class SubmitButton(BaseInput): input_type = ‘submit’ field_classes = ‘button’ if TEMPLATE_PACK == ‘uni_form’ else ‘btn’ #removed btn-primary
When you use it, you’ve got to specify the style of the button, since the “btn-primary” default is gone now. So now, when you use it in Crispy layout code, it’s clean and simple and you now have control over the styling of your buttons.
self.helper.add_input(SubmitButton('submit', 'Update',css_class='btn-primary'))
self.helper.add_input(SubmitButton('cancel', 'Cancel',css_class='btn btn-default'))
and the rendered HTML is correct:
<div class="form-actions">
<input type="submit" name="submit" value="Update" class="btn btn-primary" id="submit-id-submit">
<input type="submit" name="cancel" value="Cancel" class="btn btn-default" id="submit-id-cancel">
</div>
There’s probably a better solution which would involve adding an anchor, which is either styled like a button or wraps a button, and links back to the page which invoked the UpdateView in the first place. The anchor approach would mean one less transaction (the POST) to handle the Cancel operation.
Issue Analytics
- State:
- Created 10 years ago
- Comments:9
Please don’t make “+1” comments. There’s a reaction button for that purpose. It just wastes time and is annoying
If you’re using Bootstrap (like I think you do), you can use
FormActions
: