Django how to create a post request for multiple forms.? - django-forms

i have multiple forms in the same template, each form is linked to a button(aform button , bform button.....)when clicked gets a pop up form with some fileds, how can i save that form by creating a post request in views.py
(i know to create a POST request for a single form.) but how do i achieve that for multiple forms.
NOTE: only one form can be submitted at a time.
def example_view(request):
context = {
'aform':AForm(),
'bform':BForm(),
'cform':CForm(),
'dform':DForm()
}
template = "xyz.html"
return render(request, template, context)
how do i create a post request for multiple forms?

You can do this in following ways.
Submit your form with ajax and handle each form separately. In this way, every form will be posted in different links.
Put different URLs in the action for the two forms. Then you'll have
two different view functions to deal with the two different forms.
Read the submit button values from the POST data. You will have to send a parameter with which you can tell which
submit button was clicked.
forma = FormA(prefix="a")
formb = FormB(prefix="b")
which_form = request.GET.get('form_name')
if request.POST:
if which_form == 'a':
forma = FormA(request.POST, prefix="a")
if forma.is_valid():
obja = forma.save()
if which_form == 'b':
formB = FormB(request.POST, prefix="b")
if formb.is_valid():
objb = formb.save()

I've recently been fighting with a similar situation. I have a 'master' form which contains 3 'subsections' or 'subforms'. I thought of them as 4 forms for way too long. After searching a dozen SO posts.
I arrived at the following:
In the html, use ONE tag, which will POST to your view. You can use s or Bootstrap classes or whatever to make the HTML look like separate forms, but I only have/need one submit button. In your example, place {{aform}}, {{bform}}, {{cform}} and {{dform}} inside the single tag pair.
In the view, while building aform, etc, assign a prefix to each form class (https://docs.djangoproject.com/en/4.1/ref/forms/api/#prefixes-for-forms). In fact, that same point in the documentation says outright "You can put several Django forms inside one tag. To give each Form its own namespace, use the prefix keyword argument:"
In the POST processor of your view, use the same prefixes. This lets you resplit the combined POST data to aform, bform, cform and dform.

Related

Replace Orbeon Form with a new one asynchronously via AJAX

I am using Orbeon forms with Hybris. We have several pages linked together where a user needs to go through them in a sequence (checkout process).
The content of the Orbeon form is dynamically being determined based on actions from previous steps. E.g.
If user adds Product A to the cart on the step 1, only two fields will be visible on the form located on step 2, if he adds another (Product B) on step 1, one more field should be visible on the form.
I am using certain preprocessor class which prefills some of the hidden fields on the form and then the logic for dynamic display is on the Form itself, based on those hidden fields. This works in a simple scenario when moving back and forth, through the steps.
However, the problem is that I need to have a HTML Mini-cart displayed on the page as well (not part of Orbeon Form), which can also trigger adding/removing of the products asynchronously.
So while I am on step 2 where the form is displayed, the user can also remove/re-add some of the products -> therefore, this needs to trigger asynchronous re-rendering of the form and change the display of the form (with new fields added or removed).
I'm using AJAX for this async stuff and the problem I am facing is that a lot of Orbeon-specific Javascript files and variables is being generated when the page loads for the first time, and some random FormID is used. This FormID is different when I retrieve the new form from the back-end and when trying to replace the HTML content I'm getting various errors in the console, because old Form id is used all over the place.
Does anyone have any suggestion if this could be achieved and how to approach this problem?
Update: Example of "hidden" field glass-coverage-selected
<xf:instance id=""fr-form-instance"" xxf:exclude-result-prefixes=""#all"">
<form>
<glass-coverage-selected/>
<section-1>
<massive-exterior-walls/>
</section-1>
...
Later, a bind is created:
<xf:bind id=""section-40-bind"" ref=""section-40"" name=""section-40"" relevant=""instance('fr-form-instance')/glass-coverage-selected = 'yes'"">
<xf:bind id=""previous-glass-insurance-bind"" ref=""previous-glass-insurance"" name=""previous-glass-insurance"">
<xf:required id=""validation-156-validation"" value=""true()""/>
</xf:bind>
And that bind is used to control the visibility of certain section:
<fr:section id=""section-40-control"" bind=""section-40-bind"">
<xf:label ref=""$form-resources/section-40/label""/>
<fr:grid>
<xh:tr>
<xh:td>
<xf:select1 id=""previous-glass-insurance-control"" appearance=""full"" bind=""previous-glass-insurance-bind"" class=""previous-insurance"">
<xf:label ref=""$form-resources/previous-glass-insurance/label""/>
<xf:hint ref=""$form-resources/previous-glass-insurance/hint""/>
<xf:help ref=""$form-resources/previous-glass-insurance/help""/>
<xf:alert ref=""$form-resources/previous-glass-insurance/alert[1]"" validation=""validation-156-validation""/>
<xf:alert ref=""$form-resources/previous-glass-insurance/alert[2]""/>
<xf:itemset ref=""$form-resources/previous-glass-insurance/item"">
<xf:label ref=""label""/>
<xf:value ref=""value""/>
<xf:hint ref=""hint""/>
</xf:itemset>
</xf:select1>
</xh:td>
</xh:tr>
</fr:grid>
</fr:section>
You can manipulate the values of form fields in JavaScript, in the browser. If you want to set the value of "hidden fields", you make sure that those fields as not hidden by putting false() under Visibility for the field in Form Builder. If you do this, for security reasons, the value of the field isn't even sent to the browser by Orbeon Forms, and it can't be set from JavaScript. Instead, to be able to set the value from JavaScript, you need to hide the control with CSS. The simplest way to do this is to add the class xforms-disabled for that field in the Control Settings dialog.
Then, assuming the name of the control in Form Builder is my-control, in JavaScript you can write var control = ORBEON.jQuery('*[id $= "my-control-control"]'); ORBEON.xforms.Document.setValue(control.attr('id'), '42');. Note the -control added at the end of the name of the control. And to test this first, I recommend you don't put the CSS class, so you can more easily see if setting the value works.
For the documentation on the above setValue() and other JavaScript APIs, see the page Client-side JavaScript API.

Update template inside a view rendered from another controller

I am looking for the way to refresh a template inside a view rendered from another controller than the template's controller, I mean:
I got two controllers AdminController & UserController. And two gsps /admin/listUsers & /user/_searchResult.
Then a want to render view listUsers who have inside the template _searchResult and all right.
Now, i want to refresh the template _searchResult, but cant find how. I tryed calling render(view:"/admin/listUsers", template:"/user/_searchResult", model:[searchResult:result])
AdminController.groovy
#Secured(['ROLE_ADMIN'])
def listUsers(){
//...
}
UserController.groovy
#Secured(['ROLE_ADMIN'])
def search(){
//search users for the givven params and send result by chain if there's an action or update a template if it's needed
//in my case this method need to update the template _searchResult
}
#Secured(['ROLE_ADMIN'])
def searchResult(){
//...
[searchResult:result]
}
listUsers.gsp
//...
<formRemote name="searchForm" url="[action:"search", controller:"user"]">
//Some fields for the search
//I need to place here some hidden inputs to send which
//template i want to update or action to redirect
</formRemote>
<g:render template="/user/_searchResult"/>
//...
_searchResult.gsp
//Just itterate and print the search result in a table
I hope I have explained the problem correctly, thanks!
I don't think I entirely understand your question, but I think the source of your confusion is that the way you are naming things doesn't follow regular conventions and you're not using the right tools for the job. Let me explain...
The methods on Controllers are called Actions. They send some data (the Model) to a View to be rendered into HTML. Views can be composed from smaller, reusable fragments called Templates. (sorry if I sound like I'm being condescending here, but I'm just trying to make sure we're all on the same page).
Now, what you've called templateA is actually a View, not a Template. You're correct that templateA (your View) can call templateB to render some markup, but then having the templateB try to call a method on another Controller doesn't make sense. That's not how things flow.
If you have some logic that needs to be executed after you've sent your Model to the View, you want to use a Tag Library (http://grails.org/doc/latest/guide/theWebLayer.html#taglibs).
To summarise, here's a quick recap.
A request should only call one Action, which sends the model to only one view.
If you need to reuse logic between Controllers, move that code to a Service.
If you need to reuse markup between Views, move that markup to a Template.
If you have logic that you want to have executed after you've sent the Model to the View, use a Tag Library.
Hopefully this will point you in the right direction.
--- UPDATE ---
OK, with the real code I can see better what you're trying to achieve. Firstly, as you're using the <g:formRemote> tag, you should have a good read of the docs at http://grails.org/doc/latest/ref/Tags/formRemote.html to understand what it does.
What you will have here is 2 separate requests. The first will be a regular page load by your browser, which is handled by the listUsers() action. Once the page is then finished loading, the user will enter a search term and hit the submit button. This will fire off a second ajax request, which will be handled by the search() action. This action could use the _searchResult.gsp template to render a HTML table to display the search results. When the browser get this, it will insert it into the DOM where you've told it to put it using the "update" attribute of the <g:formRemote> tag.
The important thing here is that from the server's perspective, these are 2 separate requests that are completely independent. They both first call an action, then send a model (a Map containing some data) to a view, which renders/merges the data with HTML and sends it back to the browser.
The difference between the 2 is that the first is a complete page load by the browser, whereas for the second request, the browser only loads a small chunk of HTML (the search results table) and updates the page content without reloading it.
So your code would look more like this...
AdminController.groovy
#Secured(['ROLE_ADMIN'])
def listUsers() {
render(view:"/admin/listUsers")
}
listUsers.gsp
<g:formRemote name="searchForm" update="insertSearchResultsHere"
url="[controller: 'user', action:'search']">
<input name="searchTerm" type="text" />
</g:formRemote>
<div id="insertSearchResultsHere"></div>
UserController.groovy
#Secured(['ROLE_ADMIN'])
def search() {
// use the search term to get a List<User>
render(template: "/user/searchResult", model: [users: users])
}
_searchResult.gsp
<table>
<g:each var="user" in="${users}">
%{-- Iterate through your search results --}%
</g:each>
</table>
I solved it by placing the attribute update and rendering the template alone:
gsp:
<formRemote name="searchForm" url="[action:"search", controller:"user"]" update="divToUpdate">
//Some fields for the search
</formRemote>
<div id="divToUpdate">
<g:render template="/user/_searchResult"/>
</div>
Controller:
def search(){
render(template:"/user/_searchResult", model:[searchResult:result])
}
When i asked this question, i was new on Grails community and i was confused with the use of remoteFunction and tags that use it like remoteForm. But i had this confusion because of i had not read the documentation. So in my case, the solution was search for documentation about how to use remote tags and render. Thanks to #AndrewW for show me the way.

iTextSharp multiple actions for pushbuttonfield

In a PDF, I can set up a button to
Submit the FDF data to my RestAPI
Redirect to a webpage (to tell user 'Thanks') and that works perfectly.
But I need to do this using code... I am using iTextSharp in the following way:
pb is my pushbutton...
sURL is the URL I need the data to go to...
This is my code:
PdfFormField pff = pb.Field;
pff.SetAdditionalActions(PdfName.A, PdfAction.CreateSubmitForm(sURL, null, PdfAction.SUBMIT_XFDF));
af.ReplacePushbuttonField("submit", pff);
This does replace the button with the submit action. How do I keep the page redirect or how do I set it in code?
I have also tried PdfName.AA and PdfName.U based on examples and I am not certain what the different names are for. But nothing works. :-/
Apparently, the SetAdditionalActions() replaces the existing actions.
I have also tried using annotations and just adding a button that doesn't exist.
You are looking for a concept called chained actions as demonstrated in the PrintTimeTable example:
Chunk chunk = new Chunk("print this page");
PdfAction action = PdfAction.javaScript(
"app.alert('Think before you print!');", stamper.getWriter());
action.next(PdfAction.javaScript(
"printCurrentPage(this.pageNum);", stamper.getWriter()));
action.next(new PdfAction("http://www.panda.org/savepaper/"));
chunk.setAction(action);
In this case, we have an action that shows an alert, prints a page and redirects to an URL. These actions are chained to each other using the next() method.
In C#, this would be:
Chunk chunk = new Chunk("print this page");
PdfAction action = PdfAction.JavaScript("app.alert('Think before you print!');", stamper.Writer);
action.Next(PdfAction.JavaScript("printCurrentPage(this.pageNum);", stamper.Writer));
action.Next(new PdfAction("http://www.panda.org/savepaper/"));
chunk.SetAction(action);
See also the C# port of the book examples.

Manually bind JQuery validation after Ajax request

I'm requesting an ASP.net MVC view into a live box and the view contains form fields that have been marked up with attributes to be used by JQuery's unobtrusive validators plug-in.
The client script is not however working and my theory is that its because the validation framework is only being triggered on page load which has long since passed by the time the MVC view has been loaded into the live box.
Thus how can I let the validation framework know that it has new form fields to fix up?
Cheers, Ian.
var $form = $("form");
$form.unbind();
$form.data("validator", null);
$.validator.unobtrusive.parse(document);
// Re add validation with changes
$form.validate($form.data("unobtrusiveValidation").options);
You may take a look at the following blog post. And here's another one.
Another option, rather trick, which worked for me. Just add following line in the beginning of the partial view which is being returned by ajax call
this.ViewContext.FormContext = new FormContext();
Reference
For some reason I had to combine bjan and dfortun's answers...
So I put this in my view:
#{
this.ViewContext.FormContext = new FormContext();
}
And this execute this after the ajax call finishes:
var form = $("#EnrollmentForm");
form.unbind();
form.data("validator", null);
$.validator.unobtrusive.parse(document);
form.validate(form.data("unobtrusiveValidation").options);
I had a similar issue. I had a form that was using Ajax requests to re-display a part of the form with different form fields. I used unobtrusive validation by manually doing it on the client side using the
#Html.TextBoxFor
for my text boxes. For some reason the validation works when attempting to submit with invalid fields (i.e., the text boxes get outlined in red and the appropriate error messages display with the content I put in the
data_val_required
attribute, for example.
However, after I click a button that makes an Ajax request to modify the form with different fields and then submit again, only the red outline on the invalid fields display, but no error messages are rendered.
bjan's trick worked for me, but I still can't see what was causing the issue. All the HTML necessary to carry out the client-side validation was there I just can't figure out why the error message attribute values wouldn't display.
All I can think of is that the jQuery validation code doesn't make a second attempt to check the form fields after a submit was made.

set every single form readonly without using widgets in the model

I am trying to build a template with some forms. I have a model with about 400 attributes for one entity. Now i want to make two different templates. In one Template the attributes should be listed like django form do. In the other template the attributes should be set readonly.
I don't want to create two diffent Forms for every attribute by using widgets.
cust_form = GeneralDataForm(instance=_customer, auto_id=False, label_suffix='')
I tried inserting the widget here but it doesn't work.
using this code you can make any form readonly. are you looking for something like this?
cust_form_read_only = make_form_readonly(cust_form)
def make_form_readonly(form):
for name, field in form.fields.items():
field.widget.attrs['readonly'] = True
field.widget.attrs['disabled'] = True
return form

Resources