I have a frustrating problem with Play 2.1.1
I revisited an existing page which was working fine and added a couple of simple select statements (not multi-select). No matter what I do the values are not getting bound to the Form on bindRequest()
Here is what I have done until now.
Did alert(document.forms[0].mySelectField.value) before submit in the view (I can see the value)
Ran: play reload, play clean, play clean-all, play complile (No use)
If I replace the select statement with an text box of same name Play binds it okay.
Printed request().body().asFormUrlEncoded() in Controller. It does not even see the select field (except in case of point 3 above).
mySelectField in MyForm is private. But it has public getter/setter.
It is a simple problem but I have been at this for 4 hours now. Any suggestions? Thanks.
View:
<input type="text" value="Y" name="mySelectField" />
<!--
<select id="mySelectField" name"mySelectField" style="width: 180px;">
<option value="">All</option>
<option value="Y">Yes</option>
<option value="N">No</option>
</select>
-->
Form:
private String mySelectField;
public String getMySelectField() {
return mySelectField;
}
public void setMySelectField(String mySelectField) {
this.mySelectField= mySelectField;
}
Controller:
Form<MyForm> myFormP = Form.form(MyForm.class);
MyForm myForm = myFormP.bindFromRequest().get();
System.out.println("B. "+myForm.getMySelectField());
System.out.println("Form: "+request().body().asFormUrlEncoded());
As far as Play is concerned, there's no difference between a text field and a select. Both are encoded values in the request. I suggest you use the dev tools in chrome or firefox to see the differences in the submitted requests.
Related
I'm trying to make a page with a search function. When you first go to the page, all you have is a search bar. When you type something into the search bar and click the "submit" or "search" button, I want the value in the search box to be submitted to the controller as a string. Then, this value can be used in returning the a model back to the page. Here's what I have so far:
Search.cshtml
#{
ViewBag.Title = "Search";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#ViewBag.PageTitle
<h1>Search All Issues</h1>
<form asp-controller="Report" asp-action="Search" method="get">
<input name="searchstr" id="Search" />
<input type="submit" value="Submit" />
</form>
ReportController.cs
[HttpGet]
public ActionResult Search(string test)
{
ViewBag.PageTitle = test;
var report = _context.Reports.ToList();
return View(report);
}
What am I doing wrong here? For now, it would be nice if I can just get that ViewBag.PageTitle to appear on the page. If I can do that, then I can return the report model just the way I want.
Also, a few additional questions. Some of the stuff I've seen on stack overflow has a recommendation to do a Post in the controller. If I do that, the page errors out. Why is a get needed for this? Intuitively, it makes more sense to me to use a Post...
Turns out I was extremely close; Stephen Muecke had the correct answer. I simply needed to change my input name or parameter name.
I made this mistake as I was considering this from a C++/C standpoint where the parameter names can be irrelevant. I see now, though, that with ASP.NET MVC, you need to have the input name match the parameter name.
Thanks for the help!
I have a weird problem in my MVC app.
When the user selects a date from a drop down, it clears the StartDate and EndDate fields.
I have the following fragment of code:
<label>Start date: #Model.StartDate</label>
#Html.TextBoxFor(s => s.StartDate)
The weird thing is that you can wee where I'm outputting it in the label, the date comes out there. The textbox is unpopulated.
I've checked the produced markup and the textbox is not being populated.
<label>Start date: 19/05/2013</label>
<input id="StartDate" name="StartDate" type="text" value="" /> <br />
What am I missing here?
To add a little bit more information, when the page is initially populated the default start and end date are output. There is a bit of jQuery that empties those fields when a <select> is changed. If I comment that bit out then the fields retain their previous values as opposed to blank. Essentially, whatever is submitted to the server is output rather than the value in the model.
Essentially, whatever is submitted to the server is output rather than the value in the model.
This behaviour is actually by design. The idea being that generally the user would expect to see in the text box what they submitted to the server.
See here for a detailed explanation, and a work around.
Instead of doing this
<label>Start date: #Model.StartDate</label>
#Html.TextBoxFor(s => s.StartDate)
You should do this
<label id="someId"></label>
#Html.TextBoxFor(s => s.StartDate,new{#id="startdate"})
and using jquery on change event on your textbox you can set lablel
$("#startdate").change(function(){
var date="Start Date:"+$(this).val();
$("#someid").html(date);
});
Thinks that your model is a class named What like this:
public class What
{
public string StartDate { get; set; }
}
Then, think that your application is "MyApplication", you need to add to the view as if the view is stronglytyped:
#using MyApplication.Models;
#inherits System.Web.Mvc.WebViewPage<What>
Then all should we run as you expect
I want to use multiple select in
Chosen.
I have Skill model like,
public class Skill
{
public int Id { get; set; }
public string Name { get; set; }
}
This works in my application:
<select data-placeholder="Choose a Country..." class="chzn-select" multiple >
<option value=""></option>
<option value="United States">United States</option>
<option value="Albania">Albania</option>
<option value="Algeria">Algeria</option>
</select>
I want to replace Countries data with my data. In controller i write:
var list = MyService.LoadAllSkills();
ViewBag.Skills = new MultiSelectList(list, "Id", "Name");
In view:
#Html.ListBox("Name", ViewBag.Skills as MultiSelectList,
new { #class = "chzn-select" } )
View result of #Html.ListBox() and #Html.DropDownList() is not like <select>
I get so result:
But, I want to get result as
How can I change Chosen sample?
The only difference I can see between the hardcoded example (which you stated that is working) and the one you generate with the ListBox helper is the absence of the data-placeholder attribute. So:
#Html.ListBox(
"Countries",
ViewBag.Skills as MultiSelectList,
new { #class = "chzn-select", data_placeholder = "Choose a Country..." }
)
This should at least generate the same markup as what you said is working. If it doesn't work then probably you haven't setup the plugin correctly or you have some other javascript errors. Read the documentation of the plugin about how it should be setup.
as other dudes mentioned, it seems your problem cause is not server-side (razor), it's actually client-side (most probably your Jquery plugin initialization).
probably when the plugin initialization called the html DOM is not generated yet, put your plugin initialization script at the end of the body or inside $(document).ready() and don't forget to take a look at the console to see if there is any errors
happy coding
I was reading http://www.orchardproject.net/docs/Creating-1-n-and-n-n-relations.ashx and could not get the idea, if it is possible to easily make master detail editing, to give you concrete example i've attached screenshot from wordpress:
So there is post and post contains set of custom fields, simple 1:N relationship, everything edited in one page - you can add/edit custom field without leaving post page.
May be someone saw similar example for Orchard on internet, or could shortly describe path to achieve this by code, would be really helpful (I hope not only for me, because this is quite common case I think).
This should be possible, although not in the most 'Orchardy' way.
I've not tested any of the below so it is probably full of mistakes - but maybe Bertrand or Pszmyd will be along later today to correct me :-)
As you have probably seen you can pass a view model to a view when creating a content shape in your editor driver:
protected override DriverResult Editor(CatPart part, dynamic shapeHelper)
{
// Driver for our cat editor
var viewModel = new CatViewModel
{
Cats = _catService.GetCats() // Cats is IEnumerable<Cat>
};
return ContentShape("Parts_CatPart_Edit",
() => shapeHelper.EditorTemplate(
TemplateName: "Parts/CatPart",
Model: viewModel,
Prefix: Prefix
));
}
So we can pass in a list of items, and render it in our view like so:
#foreach(var cat in Model.Cats)
{
<span class="cat">
<p>#cat.Name</p>
<a href="...">Delete Cat</p>
</span>
}
The problem here would be posting back changes to update the model. Orchard provides an override of the Editor method to handle the postback when a part is edited, and we can revive the viewmodel we passed in the previous method:
protected override DriverResult Editor(CatPart part, IUpdateModel updater, dynamic shapeHelper)
{
var viewModel = new CatViewModel();
if (updater.TryUpdateModel(viewModel, Prefix, null, null))
{
// Access stuff altered in the Cat view model, we can then update the CatPart with this info if needed.
}
}
This works really well for basic information like strings or integers. But I've never been able to get it working with (and not been sure if it is possible to do this with) dynamic lists which are edited on the client side.
One way around this would be to set up the buttons for the items on the N-end of the 1:N relationship such that they post back to an MVC controller. This controller can then update the model and redirect the client back to the editor they came from, showing the updated version of the record. This would require you to consistently set the HTML ID/Name property of elements you add on the client side so that they can be read when the POST request is made to your controller, or create seperate nested forms that submit directly to the contoller.
So your view might become:
#foreach(var cat in Model.Cats)
{
<form action="/My.Module/MyController/MyAction" method="POST">
<input type="hidden" name="cat-id" value="#cat.Id" />
<span class="cat">
<p>#cat.Name</p>
<input type="submit" name="delete" value="Delete Cat" />
</span>
</form>
}
<form action="/My.Module/MyController/AddItem" method="POST">
<input type="hidden" name="part-id" value="<relevant identifier>" />
<input type="submit" name="add" value="Add Cat" />
</form>
Another possibility would be to create a controller that can return the relevant data as XML/JSON and implement this all on the client side with Javascript.
You may need to do some hacking to get this to work on the editor for new records (think creating a content item vs. creating one) as the content item (and all it's parts) don't exist yet.
I hope this all makes sense, let me know if you have any questions :-)
When I used the html Helper Checkbox, it produces 2 form elements. I understand why this is, and I have no problem with it except:
The un-checking of the checkbox does not seem to be in sync with the 'hidden' value.
What I mean is that when I have a bunch of checkboxes being generated in a loop:
<%=Html.CheckBox("model.MarketCategories[" & i & "].Value", category.Value)%>
and the user deselects and checkbox and the category.Value is FALSE, the code being generated is:
<input checked="checked" id="model_MarketCategories_0__Value" name="model.MarketCategories[0].Value" type="checkbox" value="true" />
<input name="model.MarketCategories[0].Value" type="hidden" value="false" />
This is wrong since the Value is False the checkbox should NOT be checked.
Any ideas why this is happening?
What's worse, is when it's submitted, it shows up as "true,false". Very frustrating.
When you check the box programmatically, it doesn't set the associated hidden field. You can easily work around this by writing the markup for the checkbox directly instead of using the MVC control.
I've had to do this myself just recently. It's a pet peeve of mine.
See this link for more information on this.
This won't work for me because I am using Strongly Typed views/controllers.
I don't use:
public ActionResult ThisLooksWeird(FormCollection result)
{
var winnars = from x in result.AllKeys
where result[x] != "false"
select x;
// yadda
}
I use:
public ActionResult ThisLooksWeird(MyCustomModelObject result)
{
foreach (KeyValuePair<MarketCategory, Boolean> o in result.Categories) {
If (o.Value == True) {
// yadda
}
}
}
Now when I adapt my code to work as suggested in your posting, the Mapping between the two controls (checkbox/hidden) is still incorrect. It takes the value of the hidden component (which is always the value which was there when the page was loaded) instead of the checkbox which is what the value should be now.
Okay, looks like David was right. It was my misunderstanding of exactly how the two fields work together that cause his solution not to work for me.
In case this helps anyone else here is my solution and how it works:
First I had to hand craft the two fields as David had described...
<input <%
If category.Value = True Then
%> checked <%
End If
%> class="filterCheckbox" id="model_MarketCategories_<%=i%>__Value" name="model.MarketCategories[<%=i %>].Value" type="checkbox" value="true" />
<input name="model.MarketCategories[<%=i%>].Value" type="hidden" value="False" />
Now a quick recap of why there are 2 fields:
// Render an additional <input type="hidden".../> for checkboxes. This
// addresses scenarios where unchecked checkboxes are not sent in the request.
// Sending a hidden input makes it possible to know that the checkbox was present
// on the page when the request was submitted.
Now the reason both of the elements have the same name is this: If the browser will ignore all other input values with the same name once it has found one with a valid value. So if your browser always returns the value of the checkbox (regardless of whether it is checked or not) then the hidden element is ignored. If on the other hand your browser does not send the checkbox value if the checkbox is not checked, then the element immediately following the checkbox will set the value of the form property to false and return THAT.
My misunderstanding was that I thought the checkbox should always store the value of actual property, so something like:
<input <%
If category.Value = True Then
%> checked <%
End If
%> class="filterCheckbox" id="model_MarketCategories_<%=i%>__Value" name="model.MarketCategories[<%=i %>].Value" type="checkbox" value="<%=category.Value %>" />
This is what was causing issues... the checkbox 'value' should always be true. The hidden 'value' should always be false. And it is the state of the checkbox (checked or not) that will determine which gets returned to your controller.
Thanks David... sometimes the answer can be right in front of you but if your brain is not ready to receive, there's nothing a fellow programmer can do ;-)