Skip to content

Commit da72806

Browse files
committed
ajaxify form submit
1 parent 91c6b0b commit da72806

File tree

5 files changed

+83
-40
lines changed

5 files changed

+83
-40
lines changed

froide/foirequest/templates/foirequest/request.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@
3636
{% for k, v in config.items %}
3737
{% if v %}<input type="hidden" name="{{ k }}" value="1" />{% endif %}
3838
{% endfor %}
39-
<request-page id="make-request" v-cloak publicbody-default-search="{{ public_body_search }}" :publicbodies="{{ publicbodies_json }}" :request-form="{{ request_form.as_json }}" :user-form="{{ user_form.as_json }}" :was-post="{{ was_post_json }}"
39+
<request-page id="make-request" v-cloak publicbody-default-search="{{ public_body_search }}" :publicbodies="{{ publicbodies_json }}" :request-form-initial="{{ request_form.as_json }}" :user-form-initial="{{ user_form.as_json }}" :was-post="{{ was_post_json }}"
4040
{% if request.user.is_authenticated %}:user-info="{{ request.user.as_json }}"{% endif %}
41-
{% if proof_form %}:proof-form="{{ proof_form.as_json }}"{% endif %}
41+
{% if proof_form %}:proof-form-initial="{{ proof_form.as_json }}"{% endif %}
4242
{% if not config.hide_similar %}:show-similar="true"{% endif %}
4343
{% if not config.hide_draft %}:show-draft="true"{% endif %}
4444
{% if config.hide_publicbody %}:hide-publicbody-chooser="true"{% endif %}

froide/foirequest/views/make_request.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from django.conf import settings
55
from django.contrib import messages
66
from django.contrib.auth.mixins import LoginRequiredMixin
7-
from django.http import Http404
7+
from django.http import Http404, JsonResponse
88
from django.shortcuts import get_object_or_404, redirect
99
from django.urls import reverse
1010
from django.utils import timezone
@@ -22,7 +22,7 @@
2222
from froide.georegion.models import GeoRegion
2323
from froide.helper.auth import get_read_queryset
2424
from froide.helper.content_urls import get_content_url
25-
from froide.helper.utils import update_query_params
25+
from froide.helper.utils import is_fetch, update_query_params
2626
from froide.proof.forms import ProofMessageForm
2727
from froide.publicbody.forms import MultiplePublicBodyForm, PublicBodyForm
2828
from froide.publicbody.models import PublicBody
@@ -630,6 +630,14 @@ def post(self, request, *args, **kwargs):
630630

631631
if not error:
632632
return self.form_valid(**form_kwargs)
633+
634+
if is_fetch(request):
635+
return JsonResponse(
636+
# make json serializeable
637+
{form_key: form.as_data() for form_key, form in form_kwargs.items()},
638+
status=400,
639+
)
640+
633641
return self.form_invalid(**form_kwargs)
634642

635643
def save_draft(self, request_form, publicbody_form):

frontend/javascript/components/makerequest/request-form.vue

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,8 @@ export default {
327327
},
328328
props: {
329329
config: {
330-
type: Object
330+
type: Object,
331+
default: null
331332
},
332333
publicbodies: {
333334
type: Array,
@@ -338,11 +339,17 @@ export default {
338339
default: null
339340
},
340341
requestForm: {
342+
required: true,
341343
type: Object
342344
},
343345
userForm: {
346+
required: true,
344347
type: Object
345348
},
349+
proofForm: {
350+
type: Object,
351+
default: null
352+
},
346353
lawType: {
347354
type: String,
348355
default: ''
@@ -379,10 +386,6 @@ export default {
379386
type: Boolean,
380387
default: false
381388
},
382-
proofForm: {
383-
type: Object,
384-
default: null
385-
},
386389
proofRequired: {
387390
type: Boolean,
388391
default: false
@@ -414,24 +417,15 @@ export default {
414417
}
415418
},
416419
computed: {
417-
nonFieldErrors() {
418-
return this.form.nonFieldErrors
419-
},
420-
form() {
421-
return this.requestForm
422-
},
423420
formFields() {
424-
return this.form.fields
421+
return this.requestForm.fields
425422
},
426423
errors() {
427-
return this.form.errors
424+
return this.requestForm.errors
428425
},
429426
userformFields() {
430427
return this.userForm.fields
431428
},
432-
usererrors() {
433-
return this.userForm.errors
434-
},
435429
nonMeaningfulSubjects() {
436430
return this.config.settings.non_meaningful_subject_regex.map(
437431
(x) => new RegExp(x, 'i')

frontend/javascript/components/makerequest/request-page.vue

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@
5050
<div v-if="requestForm.nonFieldErrors.length > 0" class="alert alert-danger">
5151
<p v-for="error in requestForm.nonFieldErrors" :key="error" v-html="error" />
5252
</div>
53+
<div v-if="fetchError" class="alert alert-danger">
54+
<strong>{{ i18n.error }}</strong>
55+
{{ fetchError }}
56+
</div>
5357

5458
<h1
5559
v-if="hidePublicbodyChooser && hasPublicBodies"
@@ -320,7 +324,7 @@
320324
:hide-public="hidePublic"
321325
:hide-publicbody-chooser="hidePublicbodyChooser"
322326
:show-draft="showDraft"
323-
@submit="submitting = true"
327+
@submit="submit"
324328
@onlinehelp-click="onlineHelpShow($event)"
325329
/>
326330
</div>
@@ -433,13 +437,13 @@ export default {
433437
type: Object,
434438
default: null
435439
},
436-
requestForm: {
440+
requestFormInitial: {
437441
type: Object
438442
},
439-
userForm: {
443+
userFormInitial: {
440444
type: Object
441445
},
442-
proofForm: {
446+
proofFormInitial: {
443447
type: Object,
444448
default: null
445449
},
@@ -489,6 +493,8 @@ export default {
489493
submitting: false,
490494
STEPS,
491495
similarSubject: '',
496+
fetchedForms: null,
497+
fetchError: null,
492498
}
493499
},
494500
provide() {
@@ -497,21 +503,17 @@ export default {
497503
}
498504
},
499505
computed: {
500-
form() {
501-
return this.requestForm
502-
},
503-
formFields() {
504-
return this.form.fields
506+
requestForm() {
507+
return this.fetchedForms?.request_form || this.requestFormInitial
505508
},
506-
userformFields() {
507-
return this.userForm.fields
509+
userForm() {
510+
return this.fetchedForms?.user_form || this.userFormInitial
508511
},
509-
conditionalProofForm() {
510-
if (this.proofForm && this.proofForm.fields.proof) {
511-
return this.proofForm
512-
} else {
512+
proofForm() {
513+
if (!this.proofForm?.fields?.proof) {
513514
return null
514515
}
516+
return this.fetchedForms?.proof_form || this.proofFormInitial
515517
},
516518
steps() {
517519
// TODO needs discussion:
@@ -752,7 +754,7 @@ export default {
752754
this.initStoreValues({
753755
scope: this.pbScope,
754756
ignoreStorage: this.config.wasPost,
755-
formFields: this.formFields,
757+
formFields: this.requestForm.fields,
756758
formCoerce: {
757759
public: coerceDjangoBool
758760
},
@@ -785,7 +787,7 @@ export default {
785787
this.initStoreValues({
786788
scope: this.pbScope,
787789
ignoreStorage: true,
788-
formFields: this.formFields,
790+
formFields: this.requestForm.fields,
789791
mutationMap: {
790792
law_type: UPDATE_LAW_TYPE
791793
}
@@ -816,7 +818,7 @@ export default {
816818
this.initStoreValues({
817819
scope: this.pbScope,
818820
ignoreStorage: this.config.wasPost,
819-
formFields: this.userformFields,
821+
formFields: this.userForm.fields,
820822
formCoerce: {
821823
private: coerceDjangoBool,
822824
claims_vip: coerceDjangoBool
@@ -845,7 +847,7 @@ export default {
845847
this.initStoreValues({
846848
scope: this.pbScope,
847849
ignoreStorage: this.config.wasPost,
848-
formFields: this.userformFields,
850+
formFields: this.userForm.fields,
849851
mutationMap: {
850852
address: UPDATE_ADDRESS
851853
}
@@ -890,6 +892,45 @@ export default {
890892
})
891893
},
892894
methods: {
895+
submit() {
896+
this.fetchError = null
897+
this.submitting = true
898+
const form = document.forms.make_request
899+
const fd = new FormData(form)
900+
fetch(form.action, {
901+
method: 'POST',
902+
body: fd,
903+
headers: { 'x-requested-with': 'fetch' },
904+
})
905+
.then((resp) => {
906+
if (resp.ok) {
907+
if (resp.redirected && resp.url) {
908+
// success: redirect
909+
document.location.href = resp.url
910+
return
911+
}
912+
console.error(resp)
913+
throw new Error('unexpected success response')
914+
}
915+
if (resp.status === 400) {
916+
// resp not ok, assume forms have errors...
917+
return resp.json()
918+
}
919+
console.error(resp)
920+
throw new Error(`${resp.status} ${resp.statusText}`)
921+
})
922+
.then((resp) => {
923+
// ...frontend will display/handle them
924+
this.fetchedForms = resp
925+
})
926+
.catch((e) => {
927+
console.error(e)
928+
this.fetchError = e.message || this.i18n.error
929+
})
930+
.finally(() => {
931+
this.submitting = false
932+
})
933+
},
893934
setFirstStep() {
894935
// this step may at this point be "remembered" from Storage
895936
// but this case is the "default"

frontend/javascript/components/makerequest/review-request.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@
167167
type="submit"
168168
class="btn btn-primary me-2 mb-3"
169169
:disabled="needCorrection"
170-
@click="$emit('submit')">
170+
@click.prevent="$emit('submit')">
171171
<i class="fa fa-send" aria-hidden="true" />
172172
{{ i18n.submitRequest }}
173173
</button>

0 commit comments

Comments
 (0)