MVC How to pass label data from view to controller? - asp.net-mvc

I am trying to pass data from view to controller. I used BeginForm and i can pass data which users enter to textbox. But I want to also pass label data because label is filled automatically and i need to save this label text to database. How can i do?
View:
#using (Html.BeginForm("Room", "Booking", FormMethod.Post))
{
<table>
<tr>
<td align="left"><lable for="eventName">Description:</lable></td>
<td><input name="eventName" id="eventName"></td>
</tr>
<tr>
<td align="left"><lable for="startDate">Start Date : </td>
<td align="left"><label id="startDate" name="startDate" /></td>
</tr>
<tr>
<td></td>
</tr>
<tr>
<td align="right" colspan="2">
<button type="submit" class="btn-primary" name="submit" id="submit">Save</button>
</td>
</tr>
<tr>
</tr>
</table>
}
Controller:
[HttpPost]
public ActionResult Room(FormCollection form)
{
using (BookingEntities ent = new BookingEntities ())
{
ReservationTBL Tbl = new ReservationTBL();
Tbl.Description = form["eventName"].ToString();
Tbl.startDate= form["startDate"].ToString();
ent.BookingTBL.Add(Tbl);
ent.SaveChanges();
}
return View();
}

The label data doesn't get send when you post your form. What you can do however is to add an input with type hidden that contains your label data.
Something like this:
<tr>
<td align="left"><label for="startDate">Start Date : </td>
<td align="left">
<label>#Model.StartDate</label>
<input type="hidden" name="startDate" value="#Model.StartDate" id="startDate"/>
</td>
</tr>

Related

How to use IsPostBack in MVC-4

I want to don't bind my dropdown list if the form state is post back. As you can see in my code I have two forms and two submit buttons. I want to keep selected value of dropdownlist after I click second submit button.
<form method="POST" action="#Url.Action("UserRoles", "PageUserRole")">
<label>Kullanıcı Grubu</label>
#Html.DropDownList("Id", Utility.GetUserGroups(), "Kullanıcı Grubu Seçiniz.")
<input type="submit" value="Listele" />
</form>
....
<form method="POST" action="#Url.Action("EditUserRoles", "PageUserRole")">
<table>
<tbody>
<tr>
<td>
İşlem
</td>
<td>
Yetki
</td>
</tr>
#for (int i = 0; i < Model.PageMenUsuserRoles.Count; i++)
{
<tr>
<td>
#Model.PageMenUsuserRoles[i].pagemenu.Name
</td>
<td>
#Html.Hidden("PageMenUsuserRoles[" + i + "].Id", Model.PageMenUsuserRoles[i].Id)
#Html.CheckBox("PageMenUsuserRoles[" + i + "].CanView", Model.PageMenUsuserRoles[i].CanView)
</td>
</tr>
}
<tr>
<td colspan="2">
<input type="submit" value="Kaydet" />
</td>
</tr>
</tbody>
</table>
</form>

Knockout with class scoped properties

I am using Knockout and have the ViewModel bound to my data object in my ASP.Net MVC 4 project quite nicely like so:
$(document).ready(function() {
properties = #Html.Raw(Json.Encode(Model));
selectedProperty = properties[0];
viewModel = { properties: ko.mapping.fromJS(#Html.Raw(Json.Encode(Model))), selectedProperty: ko.observable()};
viewModel.setItem = function(item) {
viewModel.selectedProperty(item);
}
ko.applyBindings(viewModel);
Now I want to refactor my JavaScript so that the logic is encapsulated inside a class:
RealEstate.Search = function (properties) {
this.properties = properties;
this.selectedProperty = this.properties[0];
this.viewModel = { properties: ko.mapping.fromJS(this.properties), selectedProperty: ko.observable()};
this.viewModel.setItem = function(item) {
viewModel.selectedProperty(item);
}
ko.applyBindings(this.viewModel);
}
And I am instantiating that object in my HTML page like so:
$(document).ready(function() {
search = new RealEstate.Search(#Html.Raw(Json.Encode(Model)));
}
Now, I am getting the following error:
Error: Unable to parse bindings.
Message: ReferenceError: 'properties' is undefined;
Bindings value: foreach: properties
Here is the snipped HTML for the table bound to the ViewModel:
<div id="divDataTable" data-bind="with: properties">
<table id="dataTable" class="tablesorter">
<thead>
<tr>
<th>Address
</th>
<th>
Suburb
</th>
<th>Price
</th>
<th>Beds
</th>
<th>Baths
</th>
<th>Days Listed
</th>
</tr>
</thead>
<tbody data-bind="foreach: properties">
<tr data-bind="click: $root.setItem">
<td>
<label data-bind="text: $data.Street"></label>
<input data-bind="attr: { value : $index(), id : $index(), name : $index() }" type="hidden" />
</td>
<td data-bind="text: $data.Suburb"></td>
<td data-bind="text: $data.PriceFormatted"></td>
<td data-bind="text: $data.NumOfBedrooms"></td>
<td data-bind="text: $data.NumOfBathrooms"></td>
<td data-bind="text: $data.DaysListed"></td>
</tr>
</tbody>
</table>
</div>
</section>
<div id="divProperty">
<aside class="float-right" data-bind="with: selectedProperty">
<table>
<tr>
<td>
<label data-bind="text: $data.Street"></label>
</td>
<td>
<label data-bind="text: $data.PriceFormatted"></label>
</td>
</tr>
<tr>
<td colspan="2">
<img src="#" /></td>
</tr>
<tr>
<td>Beds:
<label data-bind="text: $data.NumOfBedrooms"></label>
</td>
<td>On OZMite:
<label data-bind="text: $data.DaysListed"></label>
</td>
</tr>
<tr>
<td>Baths:
<label data-bind="text: $data.NumOfBathrooms"></label>
</td>
<td>Year built:</td>
</tr>
</table>
</aside>
I would appreciate it if someone could shed some light on what I am doing wrong.
With the data-bind="with: properties" you are already "in the context" of the properties property inside your div.
So when you write <tbody data-bind="foreach: properties"> KO tries to find the properties property inside your properties array.
What you need is to use to reference the current binding context with the $data.
So your foreach should look like this:
<tbody data-bind="foreach: $data">
...
</todby>

Trying to figure out Ajax.BeginForm

I have a view in 2 sections.
The top section I input fields and submit to save them.
In the second section I have an autocomplete textbox. I select an item in autocomplete, and when I click submit I want to add that item to a datatable.
So for the first part when I click submit I save the details via a HttpPost method on the controller.
For the second part I intend to save it via an Ajax call for the controller and then bring back a partial view with the results. I have not coded the partial view yet, that is next.
Now I am new to Ajax.BeginForm and I am struggling with it.
I was hoping that the submit button inside the Ajax.BeginForm would only apply to that part of the form.
But in fact it calls the HttpPost method for the whole form.
So how do I fix this?
My view looks like;
#using ITOF.HtmlHelpers
#model ITOF.Models.OngoingContractViewModel
#{
ViewBag.Title = "EditOngoingContractDetails";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm("EditOngoingContractDetails", "Contract", FormMethod.Post,
new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.Contract.ContractId)
<h1>Edit Ongoing Contract Details</h1>
<fieldset>
<legend>#Model.Contract.Heading</legend>
<p>Where you see <span class="error">*</span> you must enter data.</p>
<table>
<tr>
<td style="text-align: right">
#Html.LabelFor(model => model.Contract.EndDate)
</td>
<td>
#Html.EditorFor(model => model.Contract.EndDate)
</td>
</tr>
<tr>
<td style="text-align: right">
#Html.LabelFor(model => model.Contract.Organogramme)
</td>
<td>
<input type="file" id="PDF" name="file" />
#Html.HiddenFor(model => model.Contract.Organogramme)
</td>
</tr>
#if (!string.IsNullOrWhiteSpace(Model.Contract.Organogramme))
{
<tr>
<td></td>
<td>
The current organogramme is <span class="HighlightTextRed">#Model.GetOrganogrammeName()</span>
for the contract <span class="HighlightTextRed">#Model.Contract.ContractName</span><br/>
Click here to see the last saved organogramme
</td>
</tr>
}
<tr>
<td style="text-align: right">
#Html.LabelFor(model => model.Contract.AssistantRLOManagerId)
</td>
<td>
#Html.DropDownListFor(model => model.Contract.AssistantRLOManagerId, Model.AssistantRloManagerSelectList, "--N/A--")
</td>
</tr>
#if (this.TempData["SuccessMessage"] != null)
{
<tr>
<td colspan="2" class="success">#this.TempData["SuccessMessage"].ToString()</td>
</tr>
}
<tr>
<td colspan="2" style="padding-top: 20px; text-align: center;"><input type="submit" value="Save" /></td>
</tr>
</table>
</fieldset>
<fieldset>
<legend>Add an existing Site to this contract: </legend>
#using (Ajax.BeginForm("AddExistingSite", new AjaxOptions { UpdateTargetId = "siteRows" }))
{
<input type="text" name="q" style="width: 800px"
data-autocomplete="#Url.Action("SiteSearch", "DataService", new { contractId = #Model.Contract.ContractId })" />
<input type="submit" value="Add site to contract" />
}
#if (Model.SiteList.Count > 0)
{
<table id="siteDataTable" class="display">
<thead>
<tr>
<th>Main Site?</th>
<th>Type</th>
<th>Address</th>
<th>Map</th>
<th>Telephone</th>
<th>Email</th>
</tr>
</thead>
<tbody id="siteRows">
#foreach (var item in Model.SiteList)
{
<tr id="#item.SiteContract.SiteContractId">
<td>#item.SiteContract.MainSiteFlag</td>
<td>#item.Site.SiteType</td>
<td>#item.Site.Address</td>
<td>#item.Site.MapUrl</td>
<td>#item.Site.Telephone</td>
<td>#item.Site.Email</td>
</tr>
}
</tbody>
</table>
<div class="add_delete_toolbar" />
}
#Html.ListLink("Back to List")
</fieldset>
}
Oh no, you just cannot nest HTML forms. That's not supported. You will have to rethink your design. This really has absolutely nothing to do with ASP.NET MVC and things like Html.BeginForm or Ajax.BeginForm. The HTML specification simply tells you that the <form> tag cannot be nested and if you nest it you will get undefined behavior that could vary between browsers.
For example you could implement the autocomplete functionality using jquery UI autocomplete plugin and get rid of the Ajax.BeginForm.

All model and Formcollection values are null, blank or don't exist in Firefox or Chrome

During debugging, my MVC model and Formcollection are blank with no values in FireFox (15) or Chrome (latest version).
During debugging using IE (9), I can see these values just fine.
Do you know what the solution is for this? This is very serious for public facing web sites not being able to do any programming angainst these browsers.
Here is my View...
#model PDFConverterModel.ViewModels.ViewModelTemplate_Guarantors
#{
ViewBag.Title = "BHG :: PDF Generator";
}
<h2>#ViewBag.Message</h2>
<div>
<table style="width: 1000px">
<tr>
<td colspan="5">
<img alt="BHG Logo" src="~/Images/logo.gif" />
</td>
</tr>
#using (Html.BeginForm("ProcessForm", "Home", FormMethod.Post))
{
<tr>
<td>
#(Html.Kendo().IntegerTextBox()
.Name("LoanID")
.Placeholder("Enter Loan ID")
)
</tr>
<tr>
<td>#Html.LabelFor(model => model.LoanType)
#Html.DisplayFor(model => model.LoanType)
</td>
<td>
<label for="ddlDept">Department:</label>
#(Html.Kendo().DropDownList()
.Name("ddlDept")
.DataTextField("DepartmentName")
.DataValueField("DepartmentID")
.Events(e => e.Change("Refresh"))
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetDepartments", "Home");
});
})
)
</td>
</tr>
if (Model.ShowGeneratePDFBtn == true)
{
if (Model.ErrorT == string.Empty)
{
<tr>
<td colspan="5">
<u><b>#Html.Label("Templates:")</b></u>
</td>
</tr>
<tr>
#for (int i = 0; i < Model.Templates.Count; i++)
{
<td>
#Html.CheckBoxFor(model => Model.Templates[i].IsChecked)
#Html.DisplayFor(model => Model.Templates[i].TemplateId)
</td>
}
</tr>
}
else
{
<tr>
<td>
<b>#Html.DisplayFor(model => Model.ErrorT)</b>
</td>
</tr>
}
if (Model.ErrorG == string.Empty)
{
<tr>
<td colspan="5">
<u><b>#Html.Label("Guarantors:")</b></u>
</td>
</tr>
<tr>
#for (int i = 0; i < Model.Guarantors.Count; i++)
{
<td>
#Html.CheckBoxFor(model => Model.Guarantors[i].isChecked)
#Html.DisplayFor(model => Model.Guarantors[i].GuarantorFirstName) #Html.DisplayFor(model => Model.Guarantors[i].GuarantorLastName)
</td>
}
</tr>
}
else
{
<tr>
<td>
<b>#Html.DisplayFor(model => Model.ErrorG)</b>
</td>
</tr>
}
}
<tr>
<td colspan="3">
<input type="submit" name="submitbutton" id="btnRefresh" value='Refresh' />
</td>
#if (Model.ShowGeneratePDFBtn == true)
{
<td>
<input type="submit" name="submitbutton" id="btnGeneratePDF" value='Generate PDF' />
</td>
}
</tr>
<tr>
<td colspan="5">
#Model.Error
</td>
</tr>
}
</table>
</div>
<script type="text/javascript">
$('btnRefresh').on('click', '#btnRefresh', function () {
Refresh();
});
function Refresh() {
var LoanID = $("#LoanID").val();
if (LoanID != "") {
document.forms[0].submit();
}
else {
alert("Please enter a LoanId");
}
}
</script>
I know this is a very old question, but answering this might help people like who are struggling with this issue.
I had a similar issue. The problem lies here:
<table style="width: 1000px">
<tr>
<td colspan="5">
<img alt="BHG Logo" src="~/Images/logo.gif" />
</td>
</tr>
#using (Html.BeginForm("ProcessForm", "Home", FormMethod.Post))
{
<tr>
<td>
#(Html.Kendo().IntegerTextBox()
.Name("LoanID")
.Placeholder("Enter Loan ID")
)
</td>
</tr>
}
</table>
After begin form there are <tr> tags directly! Browsers like chrome and mozilla get confused in such cases. The <table> tag should be inside the form. If we look at your code, which was exactly what I had done, <table> tag was before #using Html.BeginForm.
Internet Explorer somehow understands this, but the other browsers don't.
When I did an inspect element I found that there was a form tag within each <tr> tag and it always returned FormCollection as null. Simply defining <table> within form solved my problem.
So here's how it should be:
<table style="width: 1000px">
<tr>
<td colspan="5">
<img alt="BHG Logo" src="~/Images/logo.gif" />
</td>
</tr>
<tr><td>
#using (Html.BeginForm("ProcessForm", "Home", FormMethod.Post))
{
<table>
<tr>
<td>
#(Html.Kendo().IntegerTextBox()
.Name("LoanID")
.Placeholder("Enter Loan ID")
)
</td>
</tr>
</table>
}
</td></tr>
</table>
I just found out what the issue is by experimneting.
The Telerik MVC widgets don't emit any FormCollection data!!!!
Only EditorFor and TextBoxFor emit these values, plus the input buttons.
What good are these widgets if I can't use the FormCollection values from them???? Especially the DropDownList where I can retrireve data and need the selected value to pass onto other methods.
(This would be better suited as comment, but I can't comment yet)
For future reference, here's a spec (W3C might have something different) for what gets submitted when a form is submitted:
http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#category-submit
You can look at whatever HTML was generated to make sure it gets submitted. You could also use something like Fiddler to look at the Http request

MVC Model with multiple HttpPostedFileBase properties

I'm using the following model with my get/post actions.
Public Class AuthorEditQuestionViewModel
<Required()>
<Display(Name:="Question Title")>
Public Property Title As String
<Display(Name:="Start Ledger")>
Public Property StartLedger As HttpPostedFileBase
Public Property StartLedgerUrl As String
<Display(Name:="End Ledger")>
Public Property EndLedger As HttpPostedFileBase
Public Property EndLedgerUrl As String
<Required()>
<Display(Name:="Introduction/Instructions")>
Public Property IntroductionHtml As String
End Class
The html for the ledger fields is as follows.
<input type="file" id="StartLedger" name="StartLedger" />
<input type="file" id="EndLedger" name="EndLedger" />
However, in the post action, it seems that both the StartLedger and EndLedger properties seem to be populated with the same value (the first file).
Does anyone have any examples of handling multiple named file upload fields with MVC3? It really feels like supporting file uploads well has been a shortcoming in ASP.Net MVC since version 1.
---- EDIT (.vbhtml below)
#Using Html.BeginForm("EditQuestion", "Author", Nothing, FormMethod.Post, New With {.enctype = "multipart/form-data"})
#Html.ValidationSummary("Please correct the following issues.")
#<table class="form">
<tr>
<td class="label">#Html.LabelFor(Function(m) m.Title)</td>
<td class="input">
#Html.TextBoxFor(Function(m) m.Title)
</td>
</tr>
<tr>
<td class="label">#Html.LabelFor(Function(m) m.StartLedger)</td>
<td class="input">
<input type="file" id="StartLedger" name="StartLedger" />
#If Not String.IsNullOrWhiteSpace(Model.StartLedgerUrl) Then
#Download
End If
</td>
</tr>
<tr>
<td class="label">#Html.LabelFor(Function(m) m.EndLedger)</td>
<td class="input">
<input type="file" id="EndLedger" name="EndLedger" />
#If Not String.IsNullOrWhiteSpace(Model.EndLedgerUrl) Then
#Download
End If
</td>
</tr>
<tr>
<td class="label" colspan="2">#Html.LabelFor(Function(m) m.IntroductionHtml)</td>
</tr>
<tr>
<td class="input" colspan="2">#Html.TextAreaFor(Function(m) m.IntroductionHtml, 10, 80, Nothing)</td>
</tr>
<tr>
<td class="buttons" colspan="2">
<button class="action" data-action="#Url.Action("Index")">Cancel</button>
<button>Save</button>
</td>
</tr>
</table>
End Using
The signature for the action is as follows...
Function EditQuestion(id As Guid?, model As AuthorEditQuestionViewModel) As ActionResult

Resources