In a Camunda embedded form, how do you specify the bound variable scope? - camunda

Within a user task, a segment of the embedded form markup is
...
<div class="form-group">
<label for="reference">Reference</label>
<input class="form-control"
cam-variable-name="reference"
cam-variable-type="String"
name="reference" />
</div>
...
On form entry, the reference field should be empty. On form submission, the associated Camunda process variable is populated with the reference text as a single String as expected.
Reading the Camunda manual, forums etc, there is no setting to specify the bound variable scope,
For this form field, I wish to use local variables (task scoped), not process instance scoped variables.
If process variables are used, if there is a following user task with a form using the same variable-name, that form field is populated with the previously entered value.
I understand that variables can be programmically reset and that I can use a different variable name but use of a local variable would avoid this.
Also, use of process variables results in an excessive number of variables as seen in
cockpit > running process instances > [process-name] > [instance GUID] > variables
Generally, unless the value is to be used later, form based variables have only relevance during form set-up and action processing.

To set local variables in user forms, the easiest way is to define them in a task-listener creating the task. Then you can reference the variables with cam-variable-name in the form.
Have a look at this post for further details: https://forum.camunda.org/t/variables-in-parallel-process/1476/3

Related

ColdFusion 10 getting element is undefined in form error

I've got a ColdFusion 10 form, to which I'm adding a new multiple select list
<SELECT multiple="multiple" id="icd9list"
name="icd9list"
size="2"
class="pageText2"
style="width:400px;">
</SELECT>
It shows up on the form correctly and I can get items added to it with JavaScript, but when I go to process the form, the form action page is giving the following error:
Element ICD9LIST is undefined in FORM.
I've added cfparam tags on the initial form page, as well as the form action page where I'm getting the error.
Can't for the life of me figure out why it's not passing the form element to the action page. The method is post, so it should be picking it up. All of the other form elements on the page are picked up fine.
<cfform action="updform.cfm" name="custform" method="POST">
I also tried to use custform.icd9list and got the same issue:
Element ICD9LIST is undefined in CUSTFORM.
This page is some VERY legacy code that we can't really go back and refactor too much. The only thing I'm thinking is that when the page first loads, the multiple select option is blank and then we are adding options to it via javascript from a pop-out window after the fact. When I inspect the element in Chrome, after I've added options to it, they are there, but I'm wondering if it's still being treated as a blank multiple select list. I do know that if I remove the multiple attribute and treat the form element as a single drop down list that it shows up in the form dump with a value, but only the first (or whatever selected) value.
Beginning to think the answer may be to have a hidden field with the option values populated and let the form read that.
Adding options to a multiple select list isn't enough. They have to be selected as well. Otherwise, the list isn't considered a successful control and the field won't be passed to the action page (emphasis mine)
A successful control is "valid" for submission. Every successful
control has its control name paired with its current value as part of
the submitted form data set. A successful control must be defined
within a FORM element and must have a control name.
However:
Controls that are disabled cannot be successful.
If a form contains more than one submit button, only the activated submit button is successful.
All "on" checkboxes may be successful.
For radio buttons that share the same value of the name attribute, only the "on" radio button may be successful.
For menus, the control name is provided by a SELECT element and values are provided by OPTION elements. Only selected options may be
successful. When no options are selected, the control is not
successful and neither the name nor any values are submitted to the
server when the form is submitted.
The current value of a file select is a list of one or more file names. Upon submission of the form, the contents of each file are
submitted with the rest of the form data. The file contents are
packaged according to the form's content type.
The current value of an object control is determined by the object's implementation.
I suspect the form isn't forcing the items to be "selected" before the form is submitted and that's why nothing shows up on the action page.
It sounds like you need one of two things
Either required it on the client side
<SELECT multiple="multiple" required id="icd9list" name="icd9list" size="2" class="pageText2" style="width:400px;">
...
</SELECT>
Or make sure ColdFusion can handle it not existing on the server side.
<cfparam name="icd9list" default="">
As pointed out,
<cfparam name="form.icd9list" default="">
will get an even tighter scope
How are you calling on the form? Are you using form.variable or icd9list.variable? You shouldn't have to give it an ID or name unless there are multiple forms on the page. You can just name and ID your element and reference it like this: form.name

CFWheels: Display form errors on redirectto instead of renderpage

I have a form which I am validating using CFWheels model validation and form helpers.
My code for index() Action/View in controller:
public function index()
{
title = "Home";
forms = model("forms");
allforms = model("forms").findAll(order="id ASC");
}
#startFormTag(controller="form", action="init_form")#
<select class="form-control">
<option value="">Please select Form</option>
<cfloop query="allforms">
<option value="#allforms.id#">#allforms.name#</option>
</cfloop>
</select>
<input type="text" name="forms[name]" value="#forms.name#">
#errorMessageOn(objectName="forms", property="name")#
<button type="submit">Submit</button>
#endFormTag()#
This form is submitted to init_form() action and the code is :
public function init_form()
{
title = "Home";
forms = get_forms(params.forms);
if(isPost())
{
if(forms.hasErrors())
{
// don't want to retype allforms here ! but index page needs it
allforms = model(tables.forms).findAll(order="id ASC");
renderPage(action="index");
//redirectTo(action="index");
}
}
}
As you can see from the above code I am validating the value of form field and if any errors it is send to the original index page. My problem is that since I am rendering page, I also have to retype the other variables that page need such as "allforms" in this case for the drop down.
Is there a way not to type such variables? And if instead of renderPage() I use redirectTo(), then the errors don't show? Why is that?
Just to be clear, I want to send/redirect the page to original form and display error messages but I don't want to type other variables that are required to render that page? Is there are way.
Please let me know if you need more clarification.
This may seem a little off topic, but my guess is that this is an issue with the form being rendered using one controller (new) and processed using another (create) or in the case of updating, render using edit handle form using update.
I would argue, IMHO, etc... that the way that cfWheels routes are done leaves some room for improvement. You see in many of the various framework's routing components you can designate a different controller function for POST than your would use for GET. With cfWheels, all calls are handled based on the url, so a GET and a POST would be handled by the same controller if you use the same url (like when a form action is left blank).
This is the interaction as cfwheels does it:
While it is possible to change the way it does it, the documentation and tutorials you'll find seem to prefer this way of doing it.
TL; DR;
The workaround that is available, is to have the form be render (GET:new,edit) and processing (POST:create,update) handled by the same controller function (route). Within the function...
check if the user submitted using POST
if it is POST, run a private function (i.e. handle_create()) that handles the form
within the handle_create() function you can set up all your error checking and create the errors
if the function has no errors, create (or update) the model and optionally redirect to a success page
otherwise return an object/array of errors
make the result error object/array available to view
handle the form creation
In the view, if the errors are present, show them in the form or up top somewhere. Make sure that the form action either points to self or is empty. Giving the submit button a name and value can also help in determining whether a form was submitted.
This "pattern" works pretty well without sessions.
Otherwise you can use the Flash, as that is what it was created for, but you do need to have Sessions working. their use is described here: http://docs.cfwheels.org/docs/using-the-flash and here:http://docs.cfwheels.org/v1.4/docs/flashmessages
but it really is as easy as adding this to your controller
flashInsert(error="This is an error message.");
and this to your view
<cfif flashKeyExists("error")>
<p class="errorMessage">
#flash("error")#
</p>
</cfif>

Passing variables to a function

I have a module with a view function named 'edit' and a function named 'handle_upload'.
I would like to pass two variable values, which are available in the edit function, to the handle_upload function, but I don't know how, since I don't call the handle_upload function in the view function, so I can't pass the values as parameters.
For clarity:
# my_module.py
def edit():
dynamic variable #1
dynamic variable #2
render_to_response(some_site.html, locals(), context_instance = RequestContext(request))
def handle_upload():
# here is where I would want to get both variables.
It seems to me you want the variables to be available in two separate requests to the django server - first you want to set them when the user goes to the edit view, then you want to retrieve them in another view that calls handle_upload.
There are two options here, depending on the actual data you want to pass.
Pass it to the template and add it as hidden fields in the edit form.
This might be the easiest way, but be careful with sensitive data. If you don't want malicious users to see (and even edit) this data, don't do this. Users can and will edit the hidden html fields if they have bad intentions. Don't rely on this information to be correct if it can compromise the safety of your server.
First I'd like to advise you to use render instead of render_to_response, as the latter is outdated and will soon be deprecated. render ensures you have a RequestContext object, and requires the first argument to be the actual request object:
render(request, 'some_site.html', locals())
Then in your template, inside the form:
<input type='hidden' name='name1' value='{{ dynamic_variable_1 }}' />
<input type='hidden' name='name2' value='{{ dynamic_variable_2 }}' />
Then use request.POST.get('name1') to get the value of dynamic_variable_1 etc.
Use session middleware.
This way the data will stay on the server, and will even remain to be a Python object, so this handles every kind of object (I think, not 100% sure on that).
First, ensure 'django.contrib.sessions.middleware.SessionMiddleware' is in your MIDDLEWARE_CLASSES in your settings.py. It is by default if you used Django's startapp command.
Then, do the following in edit:
request.session['name1'] = dynamic_variable1
request.session['name2'] = dynamic_variable2
Then in the view that calls handle_upload, simply do the following and pass the variables to handle_upload:
dynamic_variable1 = request.session['name1']
dynamic_variable2 = request.session['name2']
You could go for something like:
dynamic variable #1
dynamic variable #2
def edit():
global dynamic variable #1, dynamic variable #2
render_to_response(… )
def handle_upload():
global dynamic variable #1, dynamic variable #2
#…
But be carefull with global variables if you are multithreading. If you do so consider a lock ;-)
You have two options.
declare your two variables global using the global keyword
have handle_upload take two arguments, and pass the two variables in
If you aren't calling it from edit(), that means you would need to return the two variables from edit() to the call site, and then pass them into handle_upload() from there.

Django: use POST or links, which is better practice?

A noobish question to be sure.
<a href="{% url 'stuff.views.SomeView' %}/somethingnew">
<button>See something new on this page</button>
</a>
<form action="" method="post">{% csrf_token %}
<button name="somethingnew" type="submit" value=True>See something new on this page</button>
</form>
With either choice, I update some boolean variable, perform the appropriate calculations, call the page view and render a page with something new on this page. Part of the reason I use either method is to save the state of a collection of boolean variables. What is the best way 1) change a boolean variable 2) save its state 3) perform the necessary updates when the button is clicked and finally 4) render page after the underlying data has been updated?
Right now, I am using forms rather than links so that I don't need to code a url for each boolean variable. Which method is better? Will one method improve the time it takes to reload the page (assuming many boolean variables)?
1) Following the REST mindset, a POST request is in order to transmit the user input, since you are altering database objects.
2) I'd save it in the Session object if the input is not needed forever (session duration). Otherwise in the database as you are doing now.
3/4) I'd gather all the necessary info in a form. When the user commits the form in a POST request, I'd compute the data and respond with the rendered page containing the computed result. If the input variables are gathered step by step with intermittent computation, I'd just update the input form accordingly (display different choices in a combo box or something like that). Of course the transmitting could be done in an AJAXy way, too.

Dynamically set default form values in django

I'm trying to find a way to dynamically set default form values. So for example, if I add a facebook login feature on my webpage, and I can get his first name and last name from what the facebook javascript returns, I want to be able to set these values as the new "value" parameter in the given form. (basically so I'm able to put the user in my database)
I was hoping that there is some sort of
{{ form.firstname.default = Javascript.return.firstname }}
that I can insert into a template but there isn't...
Any ideas? Thank you.
Edit;; Maybe it would be better to first pass in the information into a views.py? But how would I do this? I am just considering hand writing the inputs out in the javascript field, which would be annoying...
You can set the default value of a template variable:
{{ form.firstname|default:Javascript.return.firstname }}
assuming that {{ Javascript.return.firstname }} is valid in that template context.
The code generated by Django is all server-side, its templates can't use anything which isn't available when the page is loaded. You need to use javascript to set the value.
For example, if your form looks like this:
<form id="login">
<input name="firstname" />
</form>
You could use this javascript (assuming you're using jQuery):
// Do the facebook login, set the var fname to the first name, then:
$('#login [name=firstname]').val(fname);