Why is my hidden input writing: value="value" instead of true/false? - asp.net

I have an MVC4 site, with (as part of a hidden form):
<input name="somefield" type="hidden" value="#ViewBag.Test"/>
The value of ViewBag.Test is true. The form field is posting to an input parameter of the form:
public ActionResult SomeAction(bool somefield = false, ...)
but somefield is always false. Upon investigating, I see that the source code has:
<input name="somefield" type="hidden" value="value"/>
However, I know this used to work. What has happened, and what can I do?

This behaviour changed between MVC3 and MVC4. In MVC3, if you have:
<input name="somefield" type="hidden" someprop="#(SomeBooleanExpression)"/>
it would write very literally:
<input name="somefield" type="hidden" someprop="True"/>
However, in MVC4, it follows the "checkbox" etc rules, so if the value is true you get:
<input name="somefield" type="hidden" someprop="someprop"/>
and if it is false it is omitted completely:
<input name="somefield" type="hidden"/>
To get around this, consider .ToString():
<input name="somefield" type="hidden"
someprop="#(SomeBooleanExpression.ToString())"/>
which then follows string rules rather than boolean rules.

initialized Boolean values bool something =false;
then convert this value into string like,
<input name="somefield" type="hidden" value="#something.ToString()>
OR
initialized string something ="false";
< input name="somefield" type="hidden" value="#something" >
then we can read
public ActionResult Somemethod(bool something) => you can get Boolean value here
{
}

Related

Saving record in a proper way

I have a problem with saving records to DB with Spring-Mvc and Thymeleaf.
When I click "Update" button on record, to enter the update form (included beneath), all values are in place correctly, but, when I want to subbmit, an error occur. There is no any stacktrace in console, only error in web page, that I am not able to solve.
This is my code:
Controller:
#GetMapping("/{maltId}")
public ModelAndView showMalt(#PathVariable("maltId") Long maltId) {
ModelAndView mav = new ModelAndView("malt/malt-show");
mav.addObject(maltService.findById(maltId));
return mav;
}
#GetMapping("/{maltId}/edit")
public String initUpdateMaltForm(#PathVariable("maltId") Long maltId, Model model) {
model.addAttribute("malt", maltService.findById(maltId));
return VIEWS_MALT_CREATE_OR_UPDATE_FORM;
}
#PostMapping("/{maltId}/edit")
public String processUpdateMaltForm(#Valid Malt malt, BindingResult result, #PathVariable("maltId") Long maltId) {
if (result.hasErrors()) {
return VIEWS_MALT_CREATE_OR_UPDATE_FORM;
} else {
malt.setId(maltId);
Malt savedMalt = maltService.save(malt);
return "redirect:/malt/" + savedMalt.getId();
}
}
Model:
#Column(name="malt_name")
private String maltName;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="producer_id")
private Producer producer;
#Column(name="malt_filling")
private int maltFilling;
#Column(name="malt_ebc")
private int maltEbc;
#Column(name="malt_usage")
private String maltUsage;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="country_id")
private Country country;
#ManyToMany(mappedBy="malts")
private Set<Batch> batches;
This is the view:
<body>
<form th:object="${malt}" th:action="#{/malt/}" method="post">
<input type="hidden" th:field="*{id}" />
<label>Malt name:</label>
<input type="text" class="form-control" th:field="*{maltName}" />
<label>Producer:</label>
<input type="text" class="form-control"
th:field="*{producer.producerName}" />
<label>Country:</label>
<select class="form-control" th:field="*{country.id}">
<option value="0">Select country</option>
<option th:each="country : ${countries}"
th:value="${country?.id}"
th:text="${country?.countryName}">
</option>
</select>
<label>Malt filling:</label>
<input type="text" class="form-control"
th:field="*{maltFilling}" />
<label>Malt usage:</label>
<input type="text" class="form-control"
th:field="*{maltUsage}" />
<label>Malt EBC:</label>
<input type="number" class="form-control"
th:field="*{maltEbc}" />
<button class="submit-button" type="submit">Submit</button>
</form>
</body>
When I hit Submit button, I get this error:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Wed May 15 22:46:22 CEST 2019
There was an unexpected error (type=Not Found, status=404).
No message available
I have tried couple of different approaches, but nothing helps, and since there is no stacktrace in console, I have no idea what is wrong here.
Link to repo: https://github.com/fangirsan/maruszka-new
No stack trace 404 normally indicates that there is no mapping. Since you have, potentially, provided only a part of your Controller I assume that the causation for this is the code in your view right here:
<form th:object="${malt}" th:action="#{/malt/}" method="post">
The action takes to ("/malt/"), however, your controller has not got mapping for this?!
I expect that this should fix it:
<form th:object="${malt}" th:action="#{${'/' + malt.id + '/edit'}}" method="post">
Update
Had a look at your controller and you have the following annotations on your class
#Controller
#RequestMapping("/malt")
public class MaltController{..
#RequestMapping("/malt") will now make your path to save ../malt/{id}/edit'. The code below now should work:
<form th:object="${malt}" th:action="#{${'/malt/' + malt.id + '/edit'}}" method="post">
On using "#{${...}}"
#{} is a link variable, contents within this tag will be appended to the applications root context, e.g., at Stack Overflow #{'/posts'} would result with https://stackoverflow.com/posts
The ${} is a variable expression which will return a String or the object's .toString() value.
If we want to pass a variable within #{} link variable we must include the ${} variable within it, thus resulting in :
#{${'/hope/this/helps' + yourVariable}}

How to pass variable from hidden input box to another page

I am trying to get a value from a hidden input text box to another page, but it doesn't work. How to pass variable from hidden input box to another page?
Page1.asp
<input type="hidden" name="FormID" value="<% objRS("Form_id")%>
...
<input type="hidden" name="FormID" value="<%= nFormID %>">
<input type="button" value="Open Page2" onclick=openwin();"/>
Page2.asp
<%
iFormID = Request.Form("FormID")
sSQL = "select * from Form where Form_id = " & iFormID
When I click on the Button Open Page2, it doesn't get the value of FormID.
How do I fix it to get the FormID from Page1.asp?
Updated: when I tried to add a button with this JS, it won't get the variable from Page1.asp
I added this on page1.asp:
function openwin()
{window.open("Page2.asp","mywindow","width=500,height=400"):}
<input type="hidden" name="FormID" value="<%= nFormID %>">
<input type="button" value="Open Page2" onclick=openwin();"/>
Thanks.
Since it seems like you're trying to open up a pop up window, I've added a second answer, as you are not actually POSTing any data. if you want to use a pop up, the easiest way is to put the data in the query string, like so:
function openwin()
{window.open("Page2.asp?formID=" + document.frmReport.FormID.value, "mywindow","width=500,height=400"):}
now, i notice you're using a loop to generate the formIDs and using the same NAME for each field. so you'll need to loop through the set of fields, grab each ones value, and send it along as one string in the query string:
function openwin() {
var ids = '';
for( var index = 0; index < document.frmReport.FormID.length; index++ ) {
if( ids == '' )
ids += document.frmReport.FormID[ index ].value;
else
ids += ',' + document.frmReport.FormID[ index ].value;
}
window.open("Page2.asp?FormIDs=" + ids,"mywindow","width=500,height=400");
}
and on Page2.asp, you would do:
iFormIDs = Request.QueryString("FormIDs")
sSQL = "select * from Form where Form_id in ( " & iFormIDs & " ) "
You'll notice that I changed the sql to use the IN clause, that way you can get ALL records for a given set of formIDs, even if it's just one. This obviously doesn't take into account any security precautions to prevent sql injection, but this should get you started.
first, make sure your elements are in a form block with a METHOD of POST
second, your element
<input type="hidden" name="FormID" value="<% objRS("Form_id")%>
needs to be
<input type="hidden" name="FormID" value="<%= objRS("Form_id")%>" />
<%= is shorthand for Response.Write
so page1 would look like:
<form name="myForm" method="post" action="page2.asp">
<input type="hidden" name="FormID" value="<%= objRS("Form_id")%>" />
...
<input type="hidden" name="FormID" value="<%= nFormID %>">
<input type="submit" value="Open Page2" />
</form>

Handling map-like request parameters in Spring MVC

Say I have a form for a list of questions where I need a 0/1 answer. I could easily model a static list with radios, something like
<input type="radio" name="question1" value="0">
<input type="radio" name="question1" value="1">
<br>
<input type="radio" name="question2" value="0">
<input type="radio" name="question2" value="1">
#RequestMapping("/answer")
public String answer(Integer question1, Integer question2) {
But I have a dynamic list of questions instead, where each question has a numeric ID. I therefore tried to model it like the following (the HTML is dynamically created with an iteration on the question list):
<input type="radio" name="question[42]" value="0">
<input type="radio" name="question[42]" value="1">
<br>
<input type="radio" name="question[51]" value="0">
<input type="radio" name="question[51]" value="1">
where 42 and 51 are the question id.
I was expecting to capture all values in a Map parameter of my Spring controller, like so:
#RequestMapping("/answer")
public String answer(#RequestAttribute("question") HashMap<Integer, Integer> question) {
It didn't work (the method isn't called).
I also tried with string ids:
<input type="radio" name="question['42']" value="0">
#RequestMapping("/answer")
public String answer(#RequestAttribute("question") HashMap<String, Integer> question) {
Same as before.
It only works if I use a map of string/string, but in this case I get all request parameters in the map, which I will then need to parse:
#RequestMapping("/answer")
public String answer(#RequestAttribute("question") HashMap<String, String> question) {
--> question.keys: "question[42]", "question[51]"
So what is the proper way of handling dynamic radios, or more generally map-like request parameters?
I don't know why, but it works if I put the map inside a bean:
public class QuestionForm {
private HashMap<Long, String> question;
public HashMap<Long, String> getQuestion() {
return question;
}
public void setQuestion(HashMap<Long, String> question) {
this.question = question;
}
}
#RequestMapping("/answer")
public String answer(QuestionForm questionForm) {

Strange behavior of ASP.NET MVC Razor engine with unobtrusive validation attributes

I've just faced a really strange behavior of Razor engine regarding adding unobtrusive validation attributes to inputs in forms. In some cases attributes are not added.
So, I have two similar forms on the same page with similar input elements. They must be submitted to different url's.
From model side, I have a few DataAnnotations Attributes, applied to properties to have a client-side validation.
Here is my a bit simplified code of ViewModel:
public class ApplicantPersonalInfo
{
[Required]
[Display(Name = "First Name")]
[StringLength(20, MinimumLength = 2)]
[RegularExpression(#"^[ÀàÂâÆæÇçÉéÈèÊêËëÎîÏïÔôŒœÙùÛûÜüŸÿa-zA-Z \.‘'`-]+$", ErrorMessage = "First Name is in incorrect format")]
public string FirstName { get; set; }
}
Now I want to create two forms. For every of them action url can differ dynamically (I submit them using ajaxSubmit from jQuery Form Plugin), that's why I decided not to use Html.BeginForm helper method, instead creating them with simple <form> tag. So my code is:
<form id="form1">
#Html.TextBoxFor(m => Model.FirstName, new { id = "firstName1" })
</form>
<form id="form2">
#Html.TextBoxFor(m => Model.FirstName, new { id = "firstName2" })
</form>
And the most interesting is the resulting html code:
<form id="form1">
<input data-val="true" data-val-length="The field First Name must be a string with a minimum length of 2 and a maximum length of 20." data-val-length-max="20" data-val-length-min="2" data-val-regex="First Name is in incorrect format" data-val-regex-pattern="^[ÀàÂâÆæÇçÉéÈèÊêËëÎîÏïÔôŒœÙùÛûÜüŸÿa-zA-Z \.‘'`-]+$" data-val-required="The First Name field is required." id="firstName1" name="FirstName" type="text" value=""/>
</form>
<form id="form2">
<input id="firstName2" name="FirstName" type="text" value=""/>
</form>
See? All those validation attributes are not applied to the second input!
BUT if the form is generated using Html.BeginForm, like this:
#using (Html.BeginForm("NotExistingController", "NotExisitngAtion", FormMethod.Post, new { id = "form1" }))
{
#Html.TextBoxFor(m => Model.HomeOwner.FirstName, new { id = "firstName1" })
}
<form id="form2">
#Html.TextBoxFor(m => Model.HomeOwner.FirstName, new { id = "firstName2" })
</form>
the resulting html code is with attributes in both inputs:
<form action="/NotExisitngAtion/NotExistingController" id="form1" method="post">
<input data-val="true" data-val-length="The field First Name must be a string with a minimum length of 2 and a maximum length of 20." data-val-length-max="20" data-val-length-min="2" data-val-regex="First Name is in incorrect format" data-val-regex-pattern="^[ÀàÂâÆæÇçÉéÈèÊêËëÎîÏïÔôŒœÙùÛûÜüŸÿa-zA-Z \.‘'`-]+$" data-val-required="The First Name field is required." id="firstName1" name="FirstName" type="text" value="" />
</form>
<form id="form2">
<input data-val="true" data-val-length="The field First Name must be a string with a minimum length of 2 and a maximum length of 20." data-val-length-max="20" data-val-length-min="2" data-val-regex="First Name is in incorrect format" data-val-regex-pattern="^[ÀàÂâÆæÇçÉéÈèÊêËëÎîÏïÔôŒœÙùÛûÜüŸÿa-zA-Z \.‘'`-]+$" data-val-required="The First Name field is required." id="firstName2" name="FirstName" type="text" value="" />
</form>
I'm really confused by this behavior. And I've tried - you can add as much forms as you want using Html.BeginForm - every of them will have set of validation attributes; but if you add >1 form using simple <form> tag, starting from the second one attributes are missing.
So am I missing something or it's a bug in Razor engine?

using handlebars bindAttr for checkbox

I'm using handlebars in a backbone.js rails app, and I have a Boolean field I'm populating with a checkbox.
When I load the edit page, the form is populated with the contents from the server JSON something like
{id:3,user:'test',checkbox:1}
now in my handlebar form, I want to show that the checkbox is 1.
< input type="checkbox" name="checkbox" value="1" {{#if checkbox}} {{bindAttr checkbox checked="isSelected"}}{{/if}} >
but this isn't returning the checked checkbox. I'd really like to just be able to say if checkbox==1, but I don't see how I can do that with handlebars.
Anysuggestions??
What you would usually do, is using a Boolean in the 'model'.
{
isChecked: true
}
and then
<input type="checkbox" {{bindAttr checked="isChecked"}}>
If the Boolean is true, it will render the checked property, and if the Boolean is false, it would omit the property. So if isChecked is true, then Handlebars would output
<input type="checkbox" checked>
and if isChecked were false, we would get
<input type="checkbox">
Which is what we want!
I also wrote a helper to do this. It doesn't use backbone.js, so may be an alternative for some:
Handlebars.registerHelper('checked', function(currentValue) {
return currentValue == '1' ? ' checked="checked"' : '';
});
Usage example:
<input type="checkbox" name="cbxExample" id="cbxExample" {{checked cbxExample}}/>
Would tick a checkbox if the supplied JSON was:
{"cbxExample" : "1"}
Resulting in:
<input type="checkbox" name="cbxExample" id="cbxExample" checked="checked" />
[my first post - hope that's helpful!]

Resources