I'm creating a 2-page registration process in razor. The difficulty here is gathering data (username, passwd, etc) on the first page and using hidden input variables to store the first page's data on the second.
here is my hidden code:
<div id="hidden vals" style="display:none;">
#Html.HiddenFor(model => model.userRegisterModel.UserName)
#Html.HiddenFor(model => model.userRegisterModel.studentFirstName)
#Html.HiddenFor(model => model.userRegisterModel.studentlastName)
#Html.HiddenFor(model => model.userRegisterModel.Email)
#Html.PasswordFor(model => model.userRegisterModel.Password)
#Html.PasswordFor(model => model.userRegisterModel.ConfirmPassword)
</div>
the challenge is in password and confirmpassword. I don't want to use a hidden field of password type but i want my password persisted but not revealed in page-source. but the "PasswordFor" has a side problem that it "depopulates" the values and makes the user re-populate.
So to re-state, I need my password and confirm persisted and preferably not shown to the user. Moist importantly I need my password and confirm values not hidden from "view source"
My alternative strategy is to use a session variable to store all "page 1 values" but this has other pitfalls id prefer to avoid.
Can I suggest a different approach? Instead of two-page, use two-DIV.
You can still leverage things like validation (client & remote) and make sure the user can't advance without a valid form. If there are things that need to be loaded and/or created for the second page, you can do that with Ajax and your form could still live on the page, without the use of the hidden fields or the session variables/timeouts.
<form ...>
<div id="part-one">
<!-- content... -->
</div>
<div id="part-two" style="display:none;">
<!-- content... -->
</div>
<div>
<button type="button" id="prev-div">Previous</button>
<button type="button" id="next-div">Next</button>
<button disabled="disabled" id="next-div">Submit</button>
</div>
</form>
The buttons stay visible, you can toggle the state of them with jQuery, and if your requirements change an update to your model class and view are all that is required (if you're using model binding).
Yes. Keep them in Session and access it in the second page / action method.
And Make sure to clear that particular Session variable once you read from that for persistant storage.
Related
I have simple web application written using Springboot and Thymeleaf templates. Report controller receives the data from form and builds the TestPlanReportResponse object which is added as model attribute like this:
#PostMapping("/report")
public String homeSubmit(#ModelAttribute HomeFormInput homeFormInput, Model model, Errors errors) {
final TestPlanReportResponse response = new TestPlanReportResponse(homeFormInput);
model.addAttribute("allData", response);
return "charts";
}
I can work with that data in "charts" thymeleaf template and show the data I need, but I need to send exactly the same object back to controller when button is clicked, but i getting TestPlanReportResponse
object as parameter with nulls set.
#PostMapping("/report/send")
public String sendReport(#ModelAttribute TestPlanReportResponse reportData, Model model) {
//reportData contains just nulls
}
Here is how my button is set in charts template:
<form action="#" th:action="#{/report/send}" th:object="${allData}" method="post">
<button type="submit">Send the report</button>
</form>
So my question is how to send the object back from thymeleaf template? Should i create a hidden input and put there the "allData" object just to send it back? It looks for me like dirty hack. What would be the appropriate way to pass data back? I want to have this app stateless so don't to store the data on a server side.
When I used to work with Spring and Thymeleaf and form, we had the same issue, passing the data back and forth between a form, the template, and different controllers.
And what you suggest is what we did, we used hidden input as dirty as it may look,it was the standard suggested answer, we did not find anything better.
You need to create an input, with a type a value and link it to a field, like this:
<form action="#" th:action="#{/report/send}" th:object="${allData}" method="post">
<input type="hidden" th:value="*{allDataValue1}" th:field="*{allDataField1}" />
//Do this for all your attributes/values that you wish to pass to the controller
<button class="btn btn-info btn-lg btn-block" type="submit">Send the report</button>
</form>
Though, i found this answer, you can try looking into this thread
I have a simple 'user registration' page with a 'username' field along with other fields. My requirement is 'username' should not be duplicate, for this I have written a ajax function which checks if username is duplicate and if it is duplicate it prints an error message below the 'username' field, this flow is working fine, problem occurs when I click on submit button, even with the 'username not unique' message i am able to save the page [although i can catch exception and handle it accordingly]. I know this is happening because i am just displaying the error message and not binding error to 'username' field. How can I bind error message to username field(in case of username duplicate error) so that page is not submitted until this error is removed?
Code is below
1.JQuery
function check_username(){
$("#usernamentavlberror").empty();
var developerData = {};
developerData["userName"] = $("#username").val();
$.ajax({
type: 'POST',
contentType : "application/json",
url: '/checkForDuplicateUsername',
data : JSON.stringify(developerData),
dataType : 'json',
success: function(data){
if(data == "userNameExists"){
alert("inside user")
$("#usernamentavlberror").html("UserName Not Available");
}
else {
//do perform other actions like displaying error messages etc.,
}
},
error : function(data) {
alert("error---"+data);
}
});
}
Thymeleaf page
<form action="#" th:action="#{/signup}" th:object="${user}" method=post>
<div class="form-group input-group">
<div class="input-group-prepend">
<span class="input-group-text"> <i class="fa fa-user"></i>
</span>
</div>
<input name="username" th:field="*{username}" class="form-control" placeholder="User Name" type="text" id="username">
</div>
<div class="form-group input-group" th:if="${#fields.hasErrors('username')}" th:errors="*{username}"></div>
<div class="form-group input-group" id="usernamentavlberror"></div>
.
.
</form>```
"How can I bind error message to username field(in case of username
duplicate error) so that page is not submitted until this error is
removed?"
You have to understand that Thymeleaf templates are processed on the server side so you first have to submit the page to be able to get back the errors. But this doesn't mean you cannot add some nice to have features like the one you're trying to and have both worlds working together for a better user experience.
In the first iteration I would have first implemented a signup page with Thymeleaf and Spring MVC without involving any JS code. The form should have its own validation annotations, and custom ones if needed and I would have triggered them back to the view via the standard BindingResult. So when you submit an invalid form you do the standard error handling which is happening on the server side and from the server you receive back to the client a page which already contains the html with the errors in it which you render as you already did.
So after your first iteration you decided you want to validate the username via this jQuery AJAX call which will inform the user even before the submit that his username is already used. You can do it but then you take the whole responsibility of this flow. So now we are in a state where the user is seeing the error and he's also able to click on the submit form. If he does it then the server will also respond back with a page which has the validations in it so this is let's say acceptable. You can improve it by disabling the submit button in case there are still fields with validation errors but you have to do this via some JS code again.
I have got a form (below) that is posted to an umbraco surface controller.
#using (Html.BeginUmbracoForm("AddToBasket", "Basket"))
{
<h1>#Model.productSelectionModel.Product.Title - #Model.productSelectionModel.Product.Price.ToString("C")</h1>
<ul>
#foreach (var productOption in Model.productSelectionModel.ProductOptions)
{
<li>#productOption.Option.Title</li>
#Html.DropDownList(productOption.Option.Id.ToString(), productOption.ValuesInOptions.ToSelectList(f => f.OptionValue.OptionValue1,
f => f.Id.ToString(),
"Select"));
}
</ul>
<input type="submit" value="Add To Basket">
}
When I look at the HTML rendered for this form it seems to have added a hidden field called ufprt. Does any one know what this is? Why is it being added, I'm not using it any where ( I don't think I am anyway)
Any ideas?
<input name='ufprt' type='hidden' value='6C01896EF3D5F430F9ED041DD2B0D31F89FA969A085C6F4FDEC3C9D4B906846E7AA80041CEA12573E9F58C1740893B770AAE3319FAA8FA35C89A54D301CFE31B85ADC0D3D9506D208DB068D1257C5F0D5F1B3B90FD59A5C2938EED0A2EB1168AD4573CD5D043D47A8F1AA789E988CC614686B89BE57D35DA8EAAA110044C393F' />
It is to route the form to the correct controller/action method (Umbraco has the ability to route forms via that input value rather than the typical MVC approach of using the URL). I believe this is particular to surface controllers (i.e., it wouldn't apply to a normal controller, API controller, or RenderMvcController).
It is not a CSRF token as another answer indicates. If it were, it would likely have a name of "__RequestVerificationToken" as indicated here: http://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-%28csrf%29-attacks
EDIT: This information has been added here: https://github.com/kgiszewski/LearnUmbraco7/blob/a97e85e5ad17e2ba9fc463f02c76885911046b57/Chapter%2006%20-%20Surface%2C%20WebAPI%20and%20RenderMVC%20Controllers/02%20-%20Surface%20Controllers.md#special-routing
this is probably a stupid question but I cannot figure out how to do it.
So I'm new to Scala/Lift and I read the ajax form chapter in http://simply.liftweb.net/index-4.8.html#toc-Section-4.8 but the "RedirectTo" in the example does not seem to be very "ajaxian" to me. Often in case of submitting a form via ajax, you would just partially rerender the same page, right?
So that's what I'm trying to do and am completely failing right now.
How do I let Lift rerender just a part of the same page after I submit the form via ajax?
Any hints would be appreciated. Thanks.
Basically, what I have looks like this:
<div id="main" class="lift:surround?with=default;at=content">
<h2>Welcome to your project!</h2>
<div class="lift:Test">
<div>
<form class="lift:form.ajax">
<fieldset>
<label for="name">Name:</label>
<input id="name" name="name" type=text>
<p></p>
<input id="save" type="submit" value="Save">
</fieldset>
</form>
</div>
<div>
<span id="theName">Name</span>
</div>
</div>
</div>
class Test {
def render = {
var name = ""
def process(): JsCmd = {
Thread.sleep(500)
S.notice("Entered name is: %s".format(name))
Noop
}
"#theName " #> "This shall be updated with the name given in the form above" &
"#name" #> (SHtml.text(name, name = _) ++ SHtml.hidden(process))
}
}
How would I update "theName" when submitting the form?
Have a look at http://lift.la/shtmlidmemoize-simple-ajax-updating (Example Code). There is SHtml.memoize and SHtml.idMemoize which automatically caches the HTML code. Not sure why it is not used in this example in the Simply Lift book.
You have a 2 step form right? The above poster is correct.
Save your transformation in a RequestVar.
in your above example, the method you want to save is render, so 1st memoize the transform:
private def renderTest= SHtml.memoize { render }
Then, you can save this memoized transformation in a RequestVar (lasts for 1 request), or maybe a TransientRequestVar depending on your needs.
private object testTemplate extends RequestVar(renderTest)
When you want to replay the transform, from an ajax event - testTemplate.is.applyAgain.
I might have misunderstood the original question, b/c if you want to do a 2 step form, you don't really need the memoize. The memoize is if something changes on your current form, and you want to update it via an ajax event, i.e. on click or on change, b/c normally the form wouldn't update unless you did an ajax submit.
I'm using MVC 3 with razor as the view engine and the unobtrusive client validation enabled.
I'm trying to create a form where the user has a radio button group to select their preferred contact method - either phone or email. Depending on the option selected, I want to show the appropriate textbox, but then also enable/disable the required validator for the appropriate textbox.
My markup looks something like this at the moment (Just starting out with MVC so please point out any obvious mistakes):
<div id="prefferedContact">
<p>Preferred Contact Method *</p>
<input type="radio" id="contactMethodEmail" name="PreferredContactMethod" value="email" #if (Model.PreferredContactMethod != "phone"){<text>checked="checked"</text>} /> <label for="contactMethodEmail">by email</label>
<input type="radio" id="contactMethodPhone" name="PreferredContactMethod" value="phone" #if (Model.PreferredContactMethod == "phone"){<text>checked="checked"</text>} /> <label for="contactMethodPhone">by phone</label>
</div>
<div id="contactMethodDetails" class="formItem">
<div id="emailAddressBox">
#Html.LabelFor(x => x.Email, "Email address")
#Html.TextBoxFor(x => x.Email, new { #class = "textbox" })
</div>
<div id="phoneNumberBox">
#Html.LabelFor(x => x.PhoneNumber, "Phone number")
#Html.TextBoxFor(x => x.PhoneNumber, new { #class = "textbox" })
</div>
</div>
</div>
</div>
There's some jquery function that adds an onclick event to the radio buttons to toggle between the two boxes depending on the selected value.
The Model - for these specific fields - doesn't have any required validation on it at the moment but is binding fine. Also, validation is working on other fields as expected
I really just need to get an idea of:
(a) is it possible to toggle validation on and off
(b) does this impact the ModelState validation in anyway (or do I need to customise it)
I had also thought of having the one textbox for the contact data, but I wanted to have regular expression validation for the email and for the phone number separately. If I was to have a single textbox, could I switch the validation rules on the textbox depending on the selected option???
Hope that's clear enough with enough information.
Thanks
Joel
You can perform class-level validation if you need to enforce rules based on multiple properties:
http://weblogs.asp.net/scottgu/archive/2010/12/10/class-level-model-validation-with-ef-code-first-and-asp-net-mvc-3.aspx
Unfortunately, this seems to only work server-side, so you'd have to implement custom client-side validation.
Another option would be to have two different models, one for each scenario (with common properties in a base class), but this might be a little more complicated.