I have made a formsystem (Drivea) that can be used by bridgeclubs for signing up for a bridgedrive. The first question of the signing up form (form 1) is to choose between (1) signup, (2) change their former signedup data or (3) to withdraw from the bridgedrive after signing up earlier.
When people want to change their former signedup data they have to give only a numbercode (was given in the confirmationmail after signing up) and their emailadress. Directly they get an email in which the prefilled Url is given. This prefilled Url gives another form than the first form (with the 3 choises as mentioned above) with almost the same questions. The data are picked up from the responsesheet of the first form and filed in the prefilled Url from the second form. After changing data and submit the second form the new data are copied again to the responsesheet of form 1.
In the prefilled url are the itemresponse id's with corresponding data. These numbers are given by get the url of form 2. Those numbers are used in the script of form 1 to construct the prefilled Url. This is working very good because those numbers never change as long the questions of both forms are not changing.
So far so good.
Now I am developping that in the form a bridgeclub can add an extra question (item). They are able to remove that extra item and if necessarry to bring back an extra (other) question. This is possible by a few functions I made.
However when an extra item is set in the form (and automaticly also in form 2) every time the itemresonse Id is changing of that extra question. So i am looking for a solution to find the response id of that question in form 2 before this question in the form was filled in.
In a form you kan get the Id (number) of an item by item.getId(). When the form is made those Id's are allocated directly.
To get the itemresponse id's you have to go to the form (edit) en get the prefilled Url. After filling in and submit the form the url with the itemresponse id's is shown. As mentioned above for form 2.
It seems to me logical that, as with the item id's, those itemresponse id's are already known before filling in all answers of the form to get the prefilled Url.
My question is how can I get programmaticly those itemresponse id's?
Problem solved. Response Id numbers are not necessary to get the prefilled url.
OnformSubmit (e) {
......
var formResponse = form2.createResponse();
// Prefill first name
var formItem = itemsform2[0].asTextItem();
var response = formItem.createResponse(sourcedata[i-1][2]);
formResponse.withItemResponse(response);
// Prefill insertion
var formItem = itemsform2[1].asTextItem();
var response = formItem.createResponse(sourcedata[i-1][3]);
formResponse.withItemResponse(response);
// Prefill family name
var formItem = itemsform2[2].asTextItem();
var response = formItem.createResponse(sourcedata[i-1][4]);
var url = formResponse.toPrefilledUrl();
......
}
i is the row in the response sheet of form 1, sourcedata is the answer in that row and formitem is the corresponding item in form 2.
It works very good.
Related
Users can register for various events with powermail forms on a TYPO3 6.2 site.
There is no shopping cart.
For a better ux, is it possible prefill typical fields in the register form based on the user's previous input?
For example, allow the user to control this with a checkbox "save my address for use in other forms", storing his address in a session, which can be reused to prefill the next form?
The solution is on
https://docs.typo3.org/typo3cms/extensions/powermail/ForAdministrators/GoodToKnow/SaveSession/Index.html and https://forge.typo3.org/issues/69507#change-274061
Save values to a session:
plugin.tx_powermail.settings.setup {
# Save submitted values in a session to prefill forms for further visits. Define each markername for all forms.
saveSession {
# Method "temporary" means as long as the browser is open. "permanently" could be used together with a frontend-user session. If method is empty, saveSession is deactivated.
_method =
firstname = TEXT
firstname.field = firstname
lastname = TEXT
lastname.field = lastname
}
}
[globalVar = GP:tx_powermail_pi1|field|checkboxmarkername|0 > 0]
plugin.tx_powermail.settings.setup.saveSession._method = temporary
[end]
you can do one thing for this, i think you can do this by simply using javascript.
Store one address value with one variable and after on click/check event of radio/checkbox you can make same content copy there.
var addre1 = $('.residentAddress').val();
OK, so first off, let's start with me acknowledging that the bind( ... ) way of binding Lift forms is so last week! :) I do know that, and I just haven't gone back to update this code yet. Also, I trust now that there's some really slick Lifty way to do this. That's what I seek. I'm stumped as to even how to hack something together. That said...
I have a list of Items that I initially display non-editable, and the title of each Item is an ajax-enabled link that calls to the server and replaces that line-item with an editable form of the Item (I use SetHtml to swap the form in at the < li> that listed that Item).
"parent" Items List view looks something like this
< form data-lift="form.ajax">
< div data-lift="creategamewizard?multipart=true" id="wizardform">
< ul>
< li>Item 1< /li>
< li>Item 2< /li>
< /ul>
some more form elements
< button>Submit< /button>
< input type="hidden" id='298356928734' />
< /div>
< form>
This ajax submit (via the hidden field) calls processSubmit().
The SetHtml that swaps in the editableItem form looks something like this.
NOTE: At the end of the following listing, the "save" binding has no server-side code tied to it because the "parent" submit button is already on the page, and when I put another hidden field in this binding or tried to tie any code directly to the Edit Item Save button, that code and the "parent" submit got triggered. So the approach below was to try to use the "parent" submit for both the parent submit as well as the Edit Item submit.
<a href="javascript://" onclick={ajaxOnClickHandler(editItemClickHandler(item.id.get))}>{item.title.get}</a>
def ajaxOnClickHandler(jsHandler: ()=>JsCmd) =
{
SHtml.onEvent( e => jsHandler()).toJsCmd+";return false;"
}
def editItemClickHandler(itemId: String): ()=>JsCmd = ()=>
{
trace.logAjaxComm("ExistingItem.Edit()")
JsCmds.SetHtml("LiId"+itemId, getEditableItem(promo) )
}
def getEditableItem(itemId) =
{
bind( ...
"promotitle" -> SHtml.text(editablePromo.get.promotitle.is,
(s:String) => {
trace.logUIDataManipulation("Saving new promo Title["+s+"]");
editablePromo.get.promotitle(s)
}, "id" -> "promotitle"),
"save" -> SHtml.button("Save", ()=> {})
)
}
Then when the user selects an Item, and the editable Item form is plugged in, there's "another" submit button that should ajax submit the form data for that item, and then swap back in the (now updated) nonEditable version of the data.
The problem for me is the submission. In addition to the Edit Item form above, I've got a ajaxified submit button on the "parent" non-editable list page to handle submitting some fields below the list. The Edit Item "save"-> binding adds a button, which should do (and in fact does) nothing for itself, but it does trigger the "Parent" submit button. And I route that submit to do the save of the Edit Item form.
The non-editable Item and the editable item code swaps fine, but changes made in the editable Item form is not saved, and I figured out that that was happening because the elements in the editable Item form are not being submitted at all, following is an example of a log message I don't see at all...
bind( ... "promotitle" -> SHtml.text(editablePromo.get.promotitle.is,
(s:String) => {
trace.logUIDataManipulation("Saving new promo Title["+s+"]");
editablePromo.get.promotitle(s)
}, "id" -> "promotitle")
)
In a normal ajaxified form, all element handlers are called (if there are changes to the field, I guess...) in order of rendering, with the submit/hidden elements' handlers being called last (if they're last in the bind list.
so finally, let's get around to my question:
if you're doing in-place editing like this, how do I manage 2 submit buttons (the one for the non-editable list page plus the additional one that gets added when editing an item)?
I'm sure I don't need to refresh the page, but I can't figure out how you'd do this with Ajax.
Maybe alternatively, the in-place editable form can be submitted as a non-submit ajax action, ie. somehow that doesn't trigger the parent submit?
For anyone tripping over this question, I figured I'd share the solution I eventually found...
1)The problem was that the submit (for AJAX this is the hidden html tag) happened before the editable Item's field handlers were called. So when the AJAX update that collapsed the editable Item back into just a non-Editable list item, the data hadn't yet been updated. So what was displayed in non-editable form didn't show the update, yet if I refreshed the page in the browser, the update had been saved to the database and now showed properly.
2)The reason for the mal-ordering is that Lift assigns each form tag's server-side handler an id (which are "monotonically increasing" with an additional string added to the end). That's fine until you do an ajax live-update of a form and add fields (as I did when I inserted the Editable Item fields). These newly-added fields were assigned server-side ids that came after the hidden field that got generated as part of the initial page rendering.
3)The solution was to explicitly shove the hidden field into a much higher id using S.formGroup. See here for more details...
The example from the last link below is as follows (and differs from mine in that it uses SHtml.submit, whereas I use SHtml.hidden). It adds the constant 1,000 to the submit button's server-side handler id:
"type=submit" #> S.formGroup(1000) {
SHtml.submit("Submit", process)
}
Discussion of a problem that is essentially the same as mine: https://groups.google.com/forum/#!topic/liftweb/MYJQeVlOYFM
Description of id assignment and S.formGroup under heading "Server side function order.":
https://www.assembla.com/spaces/liftweb/wiki/cool_tips
And lastly, linked to from the last link is some example code:
https://groups.google.com/forum/#!topic/liftweb/E9z7PVhogQw
So I have this use case:
I have a list of contacts on a page, and want to allow the user to add new ones to the list.
In order to add a contact, there is a form with two inputs which can be filled out and there is a button to send out the form.
This is pretty straight forward in Meteor. I bind the submit event to the form as in this snippet:
Template.contacts.events
'submit #new_contact': (event) ->
event.preventDefault()
firstName = $('#first_name').val()
lastName = $('#last_name').val()
Contacts.insert(firstName: firstName, lastName: lastName)
$('#new_contact input').val('') # Clear the inputs
So well, this is also pretty easy, but I don't like the idea of referencing specific ids in the form, getting them with JQuery and then inserting a new contact to the list. I also think this has to scale very badly, if the form had 20 fields, I'd have to search for 20 elements in the form, which doesn't seem very clean.
I'd like to know if there is a better way around this problem, like binding the form inputs to an object / collection so that it gets updated automatically when the user introduces data in the form and then only persisting it when the form gets submitted.
There is automatic support for this planned (I think), but in the meantime, you can probably get around most of your objections by using the template object:
Template.contact.events
'submit form.contact': (event, template) ->
firstName = template.find('input[name=first_name]').value
Alternatively, in the body of a event helper, this.currentTarget is the form itself.
I have an existing ASP.NET MVC 2 application that I've been asked to extend. I am adding a new feature to the site where I generate an employee assessment form based on a dynamic list of questions retrieved from our HR system. I have everything working with the exception of validation and posting the responses back to the site. Here's some details:
I retrieve a list of "Questions" from our back-end system via a web service call.
Each "Question" contains the text to display as well as the following settings:
The question Type (corresponds to textbox, textarea, radio button list or checkbox list)
If comments are allowed
If an answer is required
When applicable, the list of possible responses
To generate the form, I use a for-each loop over the list of Questions. I use the value of the QuestionType property to determine which partial view to render (one for each of the types). For example, if QuestionType == SingleChoice, that partial renders the choices as a radio button list. If comments are allowed for the question, I also render an additional textarea field to hold the user's comments.
As I said, rendering the form is working fine but now I need to:
A. Enforce when an answer is required. I'm using DataAnnotations for validation everywhere else in the solution but since I'm not working against a static model, I don't see how I can do that.
B. Post the results back to the site. For each question, there can be text entered into a textbox or textarea, a selected value for a radio button list or multiple selected values for a checkbox list. Plus, each question could also have additional text sent back in the form of a comment.
All of the examples that I've seen working with dynamic "lists" are only concerned with posting a single value for each field and it is always the same type (e.g. a list of textboxes). With the variations I have to support, plus the need to send back the entered/selected value(s) and a comment for each question, I'm stumped.
Any guidance is appreciated.
I've just finished completing exactly the same task.
I chose to write a custom model binder for my dynamic form object. The model binder pulled out a bunch of prefixed form keys for hidden fields which contained some delimited meta data about the question (i.e IsRequired, QuestionType, QuestionId etc etc)
I'm using MVC3 but I think this should all work in MVC2.
I created a ModelBinder like:
public class DynamicFormModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
// Create the object to be bound to (I had a kind of form object
// with a simple list of answer objects
DynamicForm form = new DynamicForm(new List<Answer>());
HttpRequestBase request = controllerContext.HttpContext.Request;
var keys = request.Form.AllKeys.Where(k => k.StartsWith("MyFormsKeyPrefix_Meta_"));
foreach (var key in keys)
{
// Loop over each question's meta data. Metadata will always be present
// even if the user hasn't selected an answer as it's a hidden field
// TODO: Split the meta data and pull out IsRequired, QuestionType etc
// TODO: Get all the posted form values for the question (these values
// will come from textboxes, dropdowns, checkboxes etc)
// Use a prefix like: MyFormsKeyPrefix_Answer_{QuestionId}
// textboxes & dropdowns will only ever have one value
// but checkboxes could have multiple
// TODO: If it's a mandatory question then ensure there is at least
// one posted value that is not an empty string
// If there is a validation error then add it to the model state
bindingContext.ModelState.AddModelError(key, "Field is required");
foreach(var answerHtmlName in answerHtmlNames)
{
// TODO: Loop over each posted answer and create some kind of nice
// Answer object which holds the QuestionId, AnswerId, AnswerOptionId
// and Value etc.
// Add the answer to the forms answers list
form.Answers.Add(answer);
}
}
return form;
}
}
I register the ModelBinder in Global.asax using the following:
ModelBinders.Binders.Add(typeof(DynamicForm), new DynamicFormModelBinder());
So, the action method that recieves the form post looks something like:
public ActionResult ProcessForm(DynamicForm form) {
if(ModelState.IsValid)
{
DynamicFormService.Process(form);
return RedirectToAction("TheHttpGetAction");
}
return TheHttpGetAction();
}
OK, let's start with the Html.Textbox. It is supposed to contain text read from a file. The file read is based on what the user picks from a dropdown list.
The first time it is fine. The user picks a value from the dropdown list. The controller uses that value to read some text from a file, and returns that text to the view via the view model. Everything is fine.
THen the user picks another value from the dropdown list. The controller reads a new value from a file and returns it via the view model. Debugging to the LINE BEFORE THE HTML.TEXTBOX is set in the view shows that the model contains the correct value. However, the textbox itself still shows the PREVIOUS value when the page displays!
If I switch from Html.Textbox to a plain input, type="text" html control, everything works fine. That's not so hard, but the same thing happens with my dropdown list -- I can't set the selected value in code. It always reverts to whatever was chosen last. Rendering a "select" tag with a dynamically-generated option list is a pain. I would love to be able to use Html.Dropdown.
What am I missing here?? This is such a simple thing in webforms!
When you post a form, the values that are posted are put into ModelState. When the HtmlHelper renders an html iunput element, e.g. Html.TextBoxFor(x => x.FirstName), it'll search various locations to get the value for the textbox... ModelState is before ViewData.Model in the list of locations. So there for, the previously posted value will appear in your textbox.
To fix this you could clear the ModelState value or update the ModelState value. BUT I would kinda view that as a hacky way of getting around the problem.
The real issue has more to do with the flow of the posts and requests. I would personally look into that and maybe implement the PRG (Post Redirect Get) pattern.
HTHs,
Charles
Following on from what Charles/Charlino said:
Model binding updates the ModelState object, which contains validation and model binding errors that are collected during model binding.
Inside an action method, model binding has occurred already to update the model, and generated the ModelState object. If you now update the value on the model inside the action, you must also manually update the model state (since the helpers use it to generate their HTML). Below is an example:
model.CaptchaIsValid = CaptchaService.ValidateAndExpireCaptcha(model.CaptchaAttempt);
if (!model.CaptchaIsValid)
{
ModelState.AddModelError("CaptchaAttempt", "Incorrect - please try again");
}
// I'll clear the value on each attempt, to force them to re-enter a CAPTCHA.
model.CaptchaAttempt = string.Empty;
// Since I updated the model, I must create a new ValueProvider result...
ValueProviderResult clearedValue = new ValueProviderResult(
model.CaptchaAttempt,
model.CaptchaAttempt,
CultureInfo.CurrentCulture);
// ... and update the ModelState's value.
ModelState.SetModelValue("CaptchaAttempt", clearedValue);
The biggest issue I see here is that you are trying to do a postback within MVC. That model is really not supported, and is actually way more trouble than it is worth (as it seems you are finding out). I would recommend using Ajax to update the contents of the dropdown dynamically.