View - Controller Issue in CFWheels - coldfusion

I am using CFwheels for a site that I am creating and need to use a nested view. However, when I submit the form on the popup view, the component doesn't seem to work.
Below is some test code that I am using (when I use the view in the popup as an individual page everything works fine).
Is there a specific method to make something like this happen or is something like this unsupported in CFWheels?
global.cfm - Parent View
Add New Client
<div id="createClient" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<cfinclude template="createClient.cfm">
</div>
createClient.cfm - nested view (popup)
<form method="post" action="createClient">
<input type="hidden" name="isPost" value="1" />
<table>
<div class="modal-body">
<tr>
<td>Client Brand Name:</td>
<td><input type="text" name="ClientBrandName" value="" required></td>
</tr>
<tr>
<td>Survey Referral:</td>
<td><input type="text" name="surveyReference" value="" required/></td>
</tr>
Controller of nested view
<cffunction name="createClient">
<cfif isDefined('form.isPost')>
<cfscript>
application.someComponent.someFunction(
CBname = params.clientbrandname,
sRef= params.sreferralid,
sRefname = params.surveyreference
);
</cfscript>
</cfif>
</cffunction>

I'm not directly answering your question, but you're not approaching this in a very 'wheels-y' way.
firstly, all cfwheels form + url params are pushed into the params scope, so generally, we'd be doing structkeyexists(params, "isPost") (or some such) for a start. (that's not to say that the form scope is inaccessible though).
secondly, you might find includePartial() more useful than cfinclude, as you can pass named arguments through.
Ajax/Modal calls are supported in wheels, but I'd wager you're accidentally submitting to the wrong URL; you'd need to strip the layout too.
Have a look at https://github.com/neokoenig/RoomBooking - there's several examples of bootstrap modal windows which may help.

Related

HTMX form submission with a table

I am trying to use the Click to Edit example with HTMX, by using a table.
Each row (<tr>) is a database record that looks like this:
<tr hx-target="this" hx-swap="outerHTML">
<form>
<td><input type="text" name="name" value="{{row.name}}"></td>
<td><input type="text" name="email" value="{{row.email}}"></td>
<td>
<button class="btn" hx-put="/edit/{{row.id}}">Update<buttun>
<button class="btn" hx-get="/view/{{row.id}}">Cancel</button>
</td>
</form>
</tr>
Unfortunately, when I print the request body with request.form.keys on my flask server, I see that that the request is empty ([])
It seems like the button click did not trigger the form submission with all the input fields.
How can I make the button click trigger the form submission with all the fields populated ?
Ah, just remembered: you are working with tables here. Unfortunately tables are super picky about the elements inside them, and I bet form doesn't work where you put it. If you inspect the DOM I bet you'll find that there isn't really a form element in there, so htmx isn't finding it to include the inputs.
You'll need to rework this to include the values in a different way, for example using hx-include.
Something like this:
<tr hx-target="this" hx-swap="outerHTML">
<td><input type="text" name="name" value="{{row.name}}"></td>
<td><input type="text" name="email" value="{{row.email}}"></td>
<td>
<button class="btn" hx-put="/edit/{{row.id}}"
hx-include="closest tr">
Update
<button>
<button class="btn" hx-get="/view/{{row.id}}">Cancel</button>
</td>
</tr>
If you are willing to switch from table rows to divs, the original code you had should work fine.
This is an unfortunate situation where tables are not very flexible.
update: #guettli reminded me that you can include any element and it will include all inputs below it, so you can just use closest tr in your hx-include attribute. Thanks!
Can you post what the request looks like from the chrome or firefox console?
This looks correct, in general.

Creating a structure as a button in ColdFusion

First off, I'm not really sure how to title this question so I apologize if it's vague. I am trying to create a shopping list using ColdFusion and I've ran into a bit of a snag. I want a delete button to appear next to the item that's been created. I have almost everything working, but I don't understand structures enough in ColdFusion to understand what I am doing wrong. Is it similar to a component in React.js? I ran into an issue saying that the variable "button" is not defined. I'm assuming this is because structkeyExists can't identify a single button. Why would this work for form and not for a button?
Here is my code:
<cfif structKeyExists(form, "submitButt")>
<cfquery datasource="ESC-ADD-TECH">
INSERT INTO Main(itemDesc) VALUES('#itemDesc#')
</cfquery>
</cfif>
<cfif structKeyExists(button, "delete_butt")>
<cfquery datasource="ESC-ADD-TECH">
INSERT INTO Main(itemDesc) VALUES('#itemDesc#')
</cfquery>
</cfif>
<cfquery datasource="ESC-ADD-TECH" name="items">
DELETE FROM Main
WHERE itemDesc = '#itemDesc#'
</cfquery>
<body>
<div id="myDIV" class="header">
<h2>My Shopping List</h2>
<form method="POST">
<input type="text" name="itemDesc" placeholder="Title...">
<input name="submitButt" type="submit" class="addBtn">
</form>
</div>
<cfoutput query="items">
<li>#items.itemDesc# <button class="delete" name="delete_butt">x</button></li>
</cfoutput>
</body>
Is there a way to do what I am trying to do here using a structure? Am I better off creating the button in javascript and try to create a structure as a boolean statement and just have javascript rewrite that value? Kinda just shooting in the dark here, but I would appreciate any and all help.
Thank you everyone!
So there isn't going to be a "button" structure from your form being submitted.
The first thing to remember is that a ColdFusion structure is just a collection of key/value pairs (similar to a JavaScript object), and unless the value is set, will be undefined.
In your case, the "form" struct exists because you are submitting your page back to itself with your input[type="submit"]. Which for a ColdFusion page, will create a form struct with keys for each named input within the submitted form, the values of which are pulled from those elements' value attributes.
If you are trying to use the form struct to handle deleting items, you may be better served using radio buttons/checkboxes to select which item(s) to delete, and set the action to take using the value attribute of your submit buttons.
Using your code as an example:
<cfparam name="form.action" type="string" default="none">
<cfswitch expression="#form.action#">
<cfcase value="insert">
<!---Your insert query goes here--->
</cfcase>
<cfcase value="delete">
<!---Your delete query goes here--->
</cfcase>
<cfdefaultcase></cfdefaultcase>
</cfswitch>
<!---Your select query--->
<body>
<form method="post" action="#">
<div id="myDIV" class="header">
<h2>My Shopping List</h2>
<input type="text" name="itemDesc" placeholder="Title...">
<button type="submit" name="action" value="insert">Submit</button>
</div>
<ul>
<cfoutput query="items">
<li>#items.itemDesc#
<input type="radio" name="delDesc" value="#items.itemDesc#"/>
</li>
</cfoutput>
</ul>
<button type="submit" name="action" value="delete">Delete</button>
</form>
</body>
In this case you will use form.itemDesc when inserting values, and form.delDesc when deleting items.

How can I keep form values without using session?

I have one form page with pagination. I want to keep the form values as the user goes to the previous or next page, using pagination. I know that it can be done using the session scope. However, here I don't want to use session scope. Does anyone have any ideas on how to do this without using session? Please let me know.
Here is my form page:
<cfoutput>
<form action="#buildUrl(action='survey.save_surveyresults',querystring='surveyId=#rc.surveyid#')#" method="post">
<input type="hidden" name="id" value="0">
<input type="hidden" name="surveyid" value="#rc.surveyId#">
<div class="container-fluid">
<div class="row">
<div class="control-group">
<label class="label-control" for="name">Name</label>
<div class="controls">
<input type="text" name="name" id="name" required="true" placeholder="enter your name" value="#rc.name#">
</div>
</div>
<div class="control-group">
<label class="label-control" for="email">Email</label>
<div class="controls">
<input type="text" name="email" id="email" required="true" placeholder="enter your Email" value="#rc.email#">
</div>
</div>
<cfloop query="rc.questions" startrow="#startrow#" maxrows="#perpage#">
<!--- because we have all questions and answers in query we can use switch instead calling template or view
for each question, so its simplify directory structures, questions directory is not necessary now --->
<h3>#CurrentRow#<cfif rc.questions.isrequired><strong>*</strong></cfif>. #rc.questions.question#<h3>
<cfswitch expression="#rc.questions.template#">
<fieldset>
<cfcase value="textbox">
<input type="text" class="input-xlarge" name="#template#_#questionid#" id="question_#questionid#">
</cfcase>
<cfcase value="multiplechoice">
<cfloop list="#answer#" delimiters="," index="i">
<div class="controls">
<label>
<input type="radio" name="#template#_#questionid#" id="question_#questionid#" value="#answerID#" >
<span class="lbl">#i#</span>
</label>
</div>
</cfloop>
</cfcase>
<cfcase value="multiplechoiceother">
<cfloop list="#answer#" delimiters="," index="i">
<div class="controls">
<label>
<input type="radio" name="#template#_#questionid#" id="question_#questionid#" value="#answerID#" >
<span class="lbl">#i#</span>
</label>
</div>
</cfloop>
<div class="control-group">
<label class="label-control" for="other">Other</label>
<div class="controls">
<input type="text" class="input-xlarge" name="#template#_#questionid#" id="question_#questionid#">
</div>
</div>
</cfcase>
</fieldset>
</cfswitch>
</cfloop>
<p></p><br />
<cfif startrow GT 1>
Previous
</cfif>
<cfif (startrow + perpage - 1) lt rc.questions.recordcount>
Next
<cfelse>
<button type="submit" name="submit" class="btn btn-success">Finish</button>
</cfif>
</div>
</div>
</div>
</form>
</cfoutput>
You could break the form up into different sections and have it all in one page. You can hide/show parts of the form using JavaScript based on which 'page' of the form they are one.
This makes going forward or backward in the form a snap since it is not submitted until they are done with the whole form and the values they entered will still be there.. and is pretty easy to handle with jQuery or other JavaScript libraries.
As Dan said - save submitted values in hidden fields.
One issue I see with your HTML is that Previous/Next pages are just links - not submit buttons. So make sure that when clicking those links users are submitting the form - not just going to a different url.
Here's a simple snippet of code that will embed all your form variables into hidden fields. You would place this code inside the form handler on the page you are submitting to. Note Lucas' answer as well. Your form may not be submitting correctly for reasons of badly formed..er...form.
<Cfloop collection="#form#" item="fItem">
<cfoutput>
<input type="hidden" name="#fItem#" value="#form[fItem]#"/>
</cfoutput>
</cfloop>
Again .. this would go _inside" of the form on the subsequent page. This is fairly common in multipart forms (shopping carts with multiple steps, profile entries etc).
Bear in mind that with the approaches above, you need to re-validate your form values on the server side every time you submit them (or at the very least before your final processing).
What you make up for in server memory, you may lose in terms of traffic and load times, depending on scale so I would advise that you proceed with caution. Increasing production traffic unnecessarily can result in financial impacts, and often server memory can be cheaper than extended increased traffic outlay; it comes down to your requirements and scale at the end of the day.
Shipping form variables around also increases your attack surface for malicious injection of form data, so while you may be concerned with session variables being altered on you (curious to hear more on this), you are already opening yourself up by shipping this data around as plain text. Do not rely on client-side validation for this (or any) data.

How to get the selected values

I am unable to figure out how to loop over the questionTypes and get selected questionType value. Based on the selected questionType I have to add answers for multioption questions, like in choose the correct answers we provide four choices out of which one we have to select as correct answer.
I have tried to use cfswitch but it does not seem to work:
<html>
<head> <script src="http://code.jquery.com/jquery-latest.js"></script></head>
<body>
<cfoutput>
<cfif not IsDefined('rc.questionType')>
<form class="form form-horizontal" action="#buildUrl('question.new')#" method="post">
<input type="hidden" name="surveyId" value="#rc.surveyId#">
<fieldset>
<div class="control-group">
<label class="control-label" for="questiontype">Question type</label>
<div class="controls">
<select name="questionType" onchange="this.form.submit()">
<option value="0" >Select question type</option>
<cfloop query="rc.types">
<option value="#id#">#name#</option>
</cfloop>
</select>
</div>
</div>
</fieldset>
</form>
<!--- if question type is defined, display question form --->
<cfelse>
<form class="form form-horizontal" action="#buildUrl('question.save')#" method="post">
<input type="hidden" name="id" value="0">
<input type="hidden" name="surveyId" value="#rc.data.fksurveyId#">
<input type="hidden" name="questionTypeId" value="#rc.data.fkquestionTypeId#">
<input type="hidden" name="rank" value="#rc.data.rank#">
<fieldset>
<div class="control-group">
<label class="control-label" for="question">Question</label>
<div class="controls">
<input class="input-xxlarge" type="text" name="question" id="question" required="true" placeholder="write your question">
</div>
</div>
<div class="control-group">
<label class="control-label" for="Required">Required</label>
<div class="controls">
<select name="Required">
<option value="1" selected>Yes</option>
<option value="0">No</option>
</select>
</div>
</div>
<!--- question arguments for selected type, this will be for multioption questions --->
<!--- <cfif rc.questiontype is "multiple choice (single selection),Multiple Choice (Multi Selection) with Other,Multiple Choice (Single Selection) with Other,Multiple Choice (Multi Selection)"> --->
<cfswitch expression="#rc.questiontypeid#">
<cfcase value="multiple choice (single selection),Multiple Choice (Multi Selection) with Other,Multiple Choice (Single Selection) with Other,Multiple Choice (Multi Selection)">
<div class="control-group">
<label class="control-label" for="answer">Answer</label>
<div class="controls">
<input class="input-xxlarge" type="text" name="new_answer" id="new_answer">
</div>
</div>
<div class="control-group">
<label class="control-label" for="rank">rank</label>
<div class="controls">
<input class="input-mini" type="text" name="rank" id="rank">
</div>
</div>
<div class="control-group">
<label class="control-label" for="answer">Answer</label>
<div class="controls">
<input class="input-xxlarge" type="text" name="new_answer" id="new_answer">
</div>
</div>
<div class="control-group">
<label class="control-label" for="rank">rank</label>
<div class="controls">
<input class="input-mini" type="text" name="rank" id="rank">
</div>
</div>
</cfcase>
</cfswitch>
<!--- --->
<div class="form-actions">
<button type="submit" class="btn btn-primary">Save</button>
Cancel
</div>
</fieldset>
</form>
</cfif>
<cfdump var="#rc#">
</cfoutput>
</body>
</html>
This is my controller method to add a new question:
<cffunction name="new" returntype="void" access="public">
<cfargument name="rc" type="struct" required="true">
<!---call service to get the textfields, checkboxes etc,. based on questiontype selection --->
<!--- call service to get question types for select box --->
<cfset rc.types = getQuestionService().types()>
<cfset rc.action = 'New Question'>
<!--- if user select question type --->
<cfif isdefined('arguments.rc.questionType')>
<cfset rc.data = getQuestionService().new(arguments.rc.surveyId, arguments.rc.questionType)>
</cfif>
</cffunction>
I have two forms in single page. In the first form I am selecting questionType. Based on the selected questionType I have to display an add question form.
To make sure I'm reading how this code is supposed to work:
1. This is a form to create the question, not answer it.
2. rc is a struct with your basic question definition as the keys and you have other existing code that insures that the rc structure will exist on this page.
(Rather than isDefined("rc.questionType") I'd use structKeyExists(rc, "questionType"), but that's a whole different discussion.
3. When you change the value of the Question Type, that field is submitted back and other code creates and populates the questionType key of rc struct. So isDefined('rc.questionType') should now be TRUE (moving you to the cfelse block).
4. You are now brought back to the same page with a field to enter the question, whether it's required, and you're looking for the Answer entry boxes based on the questionType.
If all of those assumptions are correct, then this is the point that you would need to loop through your options for your answers. The cfswitch/cfcase is correct, but some of those multiple choice options will need to be handled slightly differently. The ones with "Other" options will need slightly more processing on this end and on the answer tracking end. You'll have to add a text box for that checked answer.
So you'll need a little more definition for the questions in the rc struct. You need to track which one is the correct answer (a simple checkbox). If you want to allow a dynamic number of multi-choice answers, you'll need to keep track of how many answers you'll need. And you could even keep these multi-choice answer options together if you tracked whether the answer was an "Other" or not. This would also allow you to have multiple "Other"-type selections in the multi-choice options. Granted, that would reduce your choices for whether this is a multi-choice question down to just one, simply "Multiple Choice". Let the answers determine whether it's single selection or "Other" selection. And if you wanted to use radio buttons instead of check boxes for the single selects, all you'd have to do is count the answers for the question. Then you can worry about each basic questionType seperately.
The code to better track the answers (correct and "Other" options) will also need to be pulled back up, likely in the getQuestionService() function, which is where I'm assuming you're pulling your question definition and populating the rc struct.
Do you plan on using this form as an UPSERT, or is this simply an INSERT and you'll UPDATE/EDIT the questions elsewhere?
Regardless, back to your original question. The first thing I'd recommend would be to also cfdump the rc struct at the top of the page. See what data you're initially working with.
Down where you need to add your Answers, the cfswitch is the correct method. You likely aren't matching any of your cases here. Output rc.questionTypeID here to see what your value is. And I'd use an integer ID for the question type rather than the name of the question type. It'll give faster, more precise processing. When you get the correct case, you'll need to cfloop your answers here.
To select which one is the correct one, simply add a selected="selected" or checked="checked" (depending on input type) inside of a cfif that checks if the current answer is the correct answer.
Since the switch expression is set to rc.questiontypeid, the case value should be the possible rc.questiontypeid, not the question type name.

Django Upload From Template

I am looking into uploading a file from the html template. I've seen a fair amount of documentation including FileFields, ImageFields etc. However, ideally I do not want to rewrite my code.
Currently, I have a simple form on my template and I would like to have an upload function there, where, an image will be uploaded and stored into my applications media folder and if possible added to a database.
I do know that I've probably taken a long and complex route but if anyone can help it'll be great!
html.py:
<div class="row"> <div class="span1 offset5"> </bR>
<form class="form-horizontal" method="get" action="/add/submit" value="add">
<fieldset> <div class="input">
<div class="inline-inputs">
<label>Ride Name:</label><input type="text" name="name">
<label>Type:</label><input type="text" name="type">
<label>Theme:</label><input type="text" name="theme">
<label>Description:</label><textarea rows="5" name ="description"></textarea>
<label>Author:</label><input type="text" name="author">
<label>Date Released:</label>
<div id="datetimepicker" class="input-append date">
<input type="text" name="date"></input>
<span class="add-on">
<i data-time-icon="icon-time" data-date-icon="icon-calendar"></i>
</span>
</div>
<label>Thread:</label><input type="text" name="thread">
<label>Video</label><textarea rows="2" name ="video"></textarea>
<br><br>
<input class="btn btn-primary" type="submit" value="Add" />
</div> </div>
</fieldset>
</form>
</div> </div>
Currently my Views.py just takes the entered data and inserts it into a database. I want to add the ability for a file to be uploaded:
def Ride_Add_Submit(request):
name = request.GET['name']
type = request.GET['type']
theme = request.GET['theme']
description = request.GET['description']
author = request.GET['author']
releasedate=request.GET['date']
video=request.GET['video']
thread=request.GET['thread']
entry = RollerCoaster(name=name, type=type, theme=theme, description=description, releasedate=releasedate, author=author, video=video, thread=thread)
entry.save()
return TemplateResponse(request, 'Ride_Add.html')
I don't understand why you keep talking about the template here, the template has nothing whatsoever to do with anything. The handling of the upload, like all logic, is done in the view.
The file upload overview still has all the information you need. You can ignore the parts about the Django form and checking if it's valid, and simply pass the file object to your upload handling function, which that page also explains.
However you will need to change your template so that the form element uses POST instead of GET (which is almost certainly a good idea anyway), and use enctype="multipart/form-data" as also described on that page.
Finally, I really would advise you to rewrite your code to use ModelForms. Not only would it make your code much simpler, it would also do things like validate the entry to make sure all the required fields are present and are of the right types, and so on - as well as output valid HTML (for instance, you're missing for attributes in your label tags).