View issue - multiple 'delete forms' - asp.net-mvc

I have a really strange ‘bug’. I use this in my view:
<% foreach (var QualitativeGlobalFeatureValue in Model.PossibleValues)
{ %>
<% using (Html.BeginForm("DeleteQualitativeGlobalFeatureValue", "Features", FormMethod.Post, new { #class = "deleteForm" }))
{ %>
<%= QualitativeGlobalFeatureValue.Value %>
<%= Html.ActionLink("Edit", "QualitativeGlobalFeatureValueForm", new { FeatureId = Model.Id, Id = QualitativeGlobalFeatureValue.Id })%>
<%= Html.Hidden("QualitativeGlobalFeatureValueId", QualitativeGlobalFeatureValue.Id)%>
<%= QualitativeGlobalFeatureValue.Id %>
<%= Html.Hidden("FeatureId", Model.Id)%>
<input type="submit" value="Delete" class="link_button" />
<% } %>
<% } %>
This produces a bunch of forms which post to an action which then redirect to an action which in turn produces this view.
Here is some HTML:
<form action="/Features/DeleteQualitativeGlobalFeatureValue" class="deleteForm" method="post">b
Edit
<input id="QualitativeGlobalFeatureValueId" name="QualitativeGlobalFeatureValueId" value="3004" type="hidden">
3004
<input id="FeatureId" name="FeatureId" value="2103" type="hidden">
<input value="Delete" class="link_button" type="submit">
</form><form action="/Features/DeleteQualitativeGlobalFeatureValue" class="deleteForm" method="post">aa
Edit
<input id="QualitativeGlobalFeatureValueId" name="QualitativeGlobalFeatureValueId" value="9010" type="hidden">
9010
<input id="FeatureId" name="FeatureId" value="2103" type="hidden">
<input value="Delete" class="link_button" type="submit">
</form>
Now if I delete the value with the Id 9010 the resulting HTML is as follows:
<form action="/Features/DeleteQualitativeGlobalFeatureValue" class="deleteForm" method="post">b
Edit
<input id="QualitativeGlobalFeatureValueId" name="QualitativeGlobalFeatureValueId" value="9010" type="hidden">
3004
<input id="FeatureId" name="FeatureId" value="2103" type="hidden">
<input value="Delete" class="link_button" type="submit">
</form>
For some unexplainable reason it contains value="9010" rather than value="3004" although it uses the code QualitativeGlobalFeatureValue.Id
It just does not make sense. Is this some browser/caching issue? – I am using Firefox. Thanks!
Best wishes,
Christian
PS:
Actions:
[MembersOnlyAttribute]
[AcceptVerbs(HttpVerbs.Get)]
public ViewResult GlobalQualitativeFeature(string Id)
{
QualitativeGlobalFeature QualitativeGlobalFeature = null;
if (TempData["ViewData"] != null)
{
ViewData = TempData["ViewData"] as ViewDataDictionary;
}
try
{
QualitativeGlobalFeature = FeatureService.GetQualitativeGlobalFeature(Id);
}
catch (Exception e)
{
ModelState.AddModelError("Exception", e.Message);
}
return View("GlobalQualitativeFeature", QualitativeGlobalFeature);
}
[MembersOnlyAttribute]
[AcceptVerbs(HttpVerbs.Post)]
public RedirectToRouteResult DeleteQualitativeGlobalFeatureValue(string QualitativeGlobalFeatureValueId, string FeatureId)
{
try
{
FeatureService.GetQualitativeGlobalFeatureValueRepository().DbContext.BeginTransaction();
FeatureService.DeleteQualitativeGlobalFeatureValue(QualitativeGlobalFeatureValueId);
FeatureService.GetQualitativeGlobalFeatureValueRepository().DbContext.CommitTransaction();
}
catch (Exception e)
{
ModelState.AddModelError("Exception", e.Message);
FeatureService.GetQualitativeGlobalFeatureValueRepository().DbContext.RollbackTransaction();
}
TempData["ViewData"] = ViewData;
return RedirectToAction("GlobalQualitativeFeature", new { Id = FeatureId });
}

I suspect the following. You click on the delete button for the 9010. The form is posted and the POST request contains QualitativeGlobalFeatureValueId=9010. In the controller action the same view is rendered. Here's the gotcha. When you write this:
<%= Html.Hidden(
"QualitativeGlobalFeatureValueId",
QualitativeGlobalFeatureValue.Id)
%>
The HTML helper (and not only this one) will first look if there's a request parameter with the same name as the name of the field (QualitativeGlobalFeatureValueId) and will use this value instead of the one you specified as the second argument (that's the way it is, don't ask my why, it's by design). So to fix this the only way is to manually render the hidden field:
<input
id="QualitativeGlobalFeatureValueId"
name="QualitativeGlobalFeatureValueId"
value="<%= QualitativeGlobalFeatureValue.Id %>"
type="hidden"
/>

You can put breakpoints in the markup and debug as it renders through, though it doesn't allow putting breakpoints on client markup or <% lines, so you need to find a line continuation.
Are you sure that it isn't a sort reordering or something like that, maybe the results aren't sorted, and that result is later on?
HTH.

Related

MVC foreach set item.ID to model.ID

I have a form that shows all the available hotel rooms, each room has a button that does a HttpPost if clicked, I have made a property in the BookingViewModel called 'RoomID'. I would like to assign the item.RoomID to Model.RoomID so I can use it in my controller to get the id from the selected room but i'm not sure how to achieve this.
ChooseRoom View
#foreach (var item in Model.AvailableRooms)
{
<li class="room-item clearfix">
<h5>#item.Name</h5>
<div class="room-list-left">
<img src="#item.Image" alt="" />
</div>
<div class="room-list-right">
<div class="room-meta">
<ul>
<li><span>Occupancy:</span> #item.Adults Adults #item.Childs Children</li>
#if (item.SmokingRoom)
{
<li><span>Smoking Allowed:</span> Yes</li>
}
else
{
<li><span>Smoking Allowed:</span> No</li>
}
</ul>
</div>
<div class="room-price">
<p class="price">From: <span>$#item.Price</span> / Night</p>
</div>
<div class="clearboth"></div>
#using (Html.BeginForm("chooseroom", "booking", FormMethod.Post))
{
<input class="button2" type="submit" value="Select Room" />
}
BookingController
[HttpPost]
public ActionResult ChooseRoom(BookingViewModel vm)
{
BookingViewModel bookingObj = GetBooking();
bookingObj.SelectedRoom = Repository.GetRoomByID(vm.RoomID);
return View("reservation", bookingObj);
}
Thank you for your time!
update your begin form as below
#using (Html.BeginForm("chooseroom", "booking", FormMethod.Post))
{
<input type="hidden" name="RoomId" value="#item.RoomID" />
<input class="button2" type="submit" value="Select Room" />
}
Just need to provide input tags having the same name as your ViewModel property.
You could add inputs in foreach loop , it should be inside form. Something like this <input name="Model.AvailableRooms[index].RoomID" value="Id Here"/>
Or if you want to select one Room you should use ajax and post id.
If I'm not wrong you form is in loop,so you could add hidden input with id
#Html.HiddenFor(c => c.AvailableRooms[index].RoomID)

Submitting a form to ASP.NET MVC from Knockout does not bring in all the values

Here is what I have in my view in ASP.NET MVC 5
#model Entities.Coupon
#using (Html.BeginForm("coupon", "marketing", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="scsm-18 scmd-16 sclg-14">
<div class="form-group">
<label>Codes</label>
#Html.TextBoxFor(p => p.Code, new { #class = "form-control", #data_bind = "value: Code", #autofocus = true, #maxlength = "50" })
</div>
<input type="radio" name="IsPerCentOrDollar" value="1" data-bind="checked: IsPerCentOrDollar" />
<span>PercentageAmount</span>
<input type="radio" name="IsPerCentOrDollar" value="2" data-bind="checked: IsPerCentOrDollar" />
<span>DollarAmount</span>
<input type="radio" name="IsPerCentOrDollar" value="3" data-bind="checked: IsPerCentOrDollar" />
<span>FreeShipping</span>
</div>
<div class="panel-footer text-right">
<input type="submit" name="commandType" id="btnSave" class="btn btn-primary" data-bind="click:submit" value="Save" />
</div>
}
In the script:
$(document).ready(function () {
var viewModel = new CouponViewModel(couponModel);
ko.applyBindings(viewModel);
function CouponViewModel(data) {
self.Code = ko.observable(data.Code);
self.IsPerCentOrDollar = ko.observable("1");
self.DiscountLevel = ko.computed(function () {
return self.IsPerCentOrDollar();
});
};
}
Code in MVC:
[HttpPost, ActionName("coupon")]
public ActionResult coupon(Coupon coupon)
{
try
{
// some logic not yet in
}
catch (Exception ex)
{
}
return View();
}
That's all I have in there now.
In Developer tools inside the browser I can see values for self.DiscountLevel change on the selection of radio buttons.
On Submit, at MVC front the value of Code comes in but the values for DiscountLevel are not.
Any help is greatly appreciated.
Regards.
Let me expand on #StephenMuecke's comment (which has the gist of it I think).
ASP.NET MVC's default model binding will fill the argument (Coupon) with values found in the request. Only form elements are sent along with the request. You seem to expect that DiscountLevel is sent along, but it's just a JavaScript function that exists in the user's browser.
Adding something like this may solve your immediate problem:
<input type="hidden" name="DiscountLevel" data-bind="value: DiscountLevel" />
To note a related issue though: the property you have trouble with is a computed observable. However, you probably do not want to send it along as it depends entirely on IsPerCentOrDollar. Just have your server side Coupon class derive the discount level from that property too. That would also prevent users from hacking the hidden input and sending in a malicious value.

Why doesn't my List<string> bind to a series of hidden fields when using Html.Hidden()?

I'm trying to use the default model binder in asp.net mvc to bind a list of hidden fields
<input id="entity" name="entity" type="hidden" value="/string/one/here" />
<input id="entity" name="entity" type="hidden" value="/another/string/here" />
<input id="entity" name="entity" type="hidden" value="/last/string/here" />
To a List<string> like this:
[HttpPost]
public ActionResult Move(List<string> entity)
{
return View(entity);
}
When I post the form, the view displays the contents of the list like this:
<%foreach (string item in Model)
{%>
<%: Html.Hidden("entity", item)%>
<!--binding not working correctly -->
<%} %>
And the generated content is this:
<input id="entity" name="entity" type="hidden" value="/last/string/here" />
<input id="entity" name="entity" type="hidden" value="/last/string/here" />
<input id="entity" name="entity" type="hidden" value="/last/string/here" />
I'm confuseled. I tried changing the initial hidden field to this:
<input id="entity__" name="entity[]" type="hidden" value="/string/one/here" />
<input id="entity__" name="entity[]" type="hidden" value="/another/string/here" />
<input id="entity__" name="entity[]" type="hidden" value="/last/string/here" />
But when I tried posting that I got this error:
System.NullReferenceException: Object reference not set to an instance of an object.
on this line of code in the view:
<%foreach (string item in Model)
I've been able to bind list of strings before... without using an index in the name. I don't understand why this isn't working correctly. Maybe a fresh set of eyes could help me out with this?
Thanks
edit
In continuing to expirement. I ditched the HtmlHelper and hardcoded a hidden field inside the foreach loop like this:
<%foreach (string item in Model)
{%>
<input id="entity" name="entity" type="hidden" value="<%:item %>" />
<%} %>
This worked. I have no idea what the difference is between the Html helper's code and this so I put the two side by side and tried to match them up.
<input id="entity" name="entity" type="hidden" value="//Content/files/NewDirectory/Aesculuparviflora011cm.jpg" />
<input id="entity" name="entity" type="hidden" value="//Content/files/NewDirectory/Aesculuparviflora011cm.jpg" />
They are identical. But the binding works when I hardcode tags and it doesn't work when i use the html helper. What gives?????????
Why are you using loops and non-strongly typed helpers in a strongly typed view? Things could be so simple with editor templates:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new[]
{
"/string/one/here", "/another/string/here", "/last/string/here"
});
}
[HttpPost]
public ActionResult Index(List<string> items)
{
return View(items);
}
}
and the corresponding view (~/Views/Home/Index.aspx):
<%# Page
Title=""
Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<IEnumerable<string>>" %>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<% using (Html.BeginForm()) { %>
<%: Html.EditorForModel() %>
<input type="submit" value="OK" />
<% } %>
</asp:Content>
and the corresponding editor template (~/Views/Home/Index/EditorTemplates/string.ascx):
<%# Control
Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<string>" %>
<%: Html.HiddenFor(x => x) %>
Now you no longer need to worry about values not properly binding, writing loops in your views, ... you can finally concentrate on the real business logic of the application.
try:
<input id="entity" name="entity0" type="hidden" value="/last/string/here" />
<input id="entity" name="entity1" type="hidden" value="/last/string/here" />
<input id="entity" name="entity2" type="hidden" value="/last/string/here" />
I actually cannot recreate your problem:
This is my code, I tried fiddling with it and I cannot get it to malfunction.
perhaps check so that your view inherits the right type. Please post all of your code neccessary to make it malfunction.
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
var strings = new string[] { "test1", "test2", "test3" };
return View(strings);
}
[HttpPost]
public ActionResult Index(List<string> strings)
{
return View(strings);
}
aspx page
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<string>>" %>
<%using (Html.BeginForm()) { %>
<% foreach (var item in Model) { %>
<%:Html.Hidden("strings", item)%>
<% } %>
<input type="submit" value="Submit" />
<% } %>

Resource not found when calling ActionResult from Controller from multiple submit buttons

link text
I am following the answer in this link, I have done this...
<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" name="submitButton" value="Send" />
<input type="submit" name="submitButton" value="Cancel" />
<% Html.EndForm(); %>
<% Html.BeginForm("Send", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Send" />
<% Html.EndForm(); %>
<% Html.BeginForm("Cancel", "MyController", FormMethod.Post); %>
<input type="submit" name="button" value="Cancel" />
<% Html.EndForm(); %>
With this in the controller...
public class MyController : Controller {
public ActionResult MyAction(string submitButton) {
switch(submitButton) {
case "Send":
// delegate sending to another controller action
return(Send());
case "Cancel":
// call another action to perform the cancellation
return(Cancel());
default:
// If they've submitted the form without a submitButton,
// just return the view again.
return(View());
}
}
private ActionResult Cancel() {
// process the cancellation request here.
return(View("Cancelled"));
}
private ActionResult Send() {
// perform the actual send operation here.
return(View("SendConfirmed"));
}
}
But I keep getting a Resource not found error - Cannot find MyController\MyAction
Don't specify "Controller" in the Form parameter:
<% Html.BeginForm("MyAction", "My", FormMethod.Post); %>
<input type="submit" name="submitButton" value="Send" />
<input type="submit" name="submitButton" value="Cancel" />
<% Html.EndForm(); %>
Link will be /My/MyAction if you want it to be MyController, the Controller class must be called MyControllerController (not tested though)
You may need to ensure you have a route that MVC can match to your Controller/Action. Something like:
routes.MapRoute(
"MyRoute",
"{controller}/{action}/{submitButton}",
new { controller = "MyController", action = "MyAction", submitButton = "Default" }
);

Passing parameters in MVC

Thare is two forms in a page first one for searching and another for deleting....
<table><tr><td>
<% using(Html.BeginForm("ViewList","ControllerName",
[values],FormMethod.Post,new{id="viewListForm"}))
{ %>
Name: <%=Html.TextBox("Name", "[value]", new { maxlength = "250" })%>
Location: <%=Html.TextBox("Location", "[Value]", new { maxlength = "250" })%>
<input type="submit" id="Search" name="Search" value="Search" />
<% } %>
</td></tr>
<tr><td>
<% using(Html.BeginForm("DeleteList","ControllerName",
new { name=?,location=? },[values],FormMethod.Post,
new{id="deleteListForm"}))
{ %>
[here the code for all items displayed in a table.]
<input type="submit" id="Delete" name="Delete" value="Delete" />
When delete buttom pressed i need to pass two parameters ie name
and location. The values of name and location are in the above viewListForm.
How i take this value from the viewListForm at run time ?
<% } %>
</td></tr><table>
Use javascript to populate hidden inputs.
Or use javascript to dynamically change the action of the search form.
Or dynamically create a form in jQuery for example and submit it.
You will need to have a controller action that takes a FormCollection as parameter
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ActionName(FormCollection collection)
{
// you can pull key value pair from the posted collection
string formValue = collection["InputId"]
}

Resources