Save all data of MVC4 html grid - asp.net-mvc

Can anyone give me an example of saving all html grid data in one time. I have a view like this.
#model IList<SURVEY.Models.Question>
#using (Html.BeginForm("Index", "Survey", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { #class = "form-3" }))
{
#foreach(var item in Model)
{
<tr>
<td>#item.Ans1</td>
<td align="center">
<label>
<input type="radio" name="optionAS_#item.QuestionId" value="1" id="optionAS_1" onclick="disableAs(this,#item.QuestionId,1)"/>
</label>
</td>
<td align="center">
<label>
<input type="radio" name="optionAS_#item.QuestionId" value="2" id="optionAS_1" onclick="disableAs(this,#item.QuestionId,2)"/>
</label>
</td>
</tr>
}
}
I am getting null value for these controls in controller post.
[HttpPost]
public ActionResult Index(IList<Question> ques)
{
return View();
}
I am getting ques is null here. Can anyone tell me how can I resolve this?

You should use html helpers to bind properties of your model, your code might be as follows:
#for(var i = 0; i < Model.Count; i++)
{
<tr>
<td>#Html.HiddenFor(_ => Model[i].Id)
Model[i].Ans1
</td>
<td align="center">
<label>
#Html.RadioButtonFor(_ => Model[i].Name)
</label>
</td>
...
</tr>
}
and so for. HiddenFor helper is needed to create hidden input to send Id value to server to give you ability to identify you object. Take a look into Html Helpers in MVC and you will have your model back to server when form is submitted.

Related

How to take data from get and put it to post? Handle input radio type

The form sends a get request and gets the following view
#using System.Linq;
#model List<Searchphone>
<h2 class="search1"></h2>
<form class="priceeconom1" method="post" asp-action="Index" asp-controller="Home">
#foreach (var p in Model)
<table>
{
<tr class="searchdata">
<td class="flight">#p.ColourPhone</td>
<td class="fromtable">#p.TypePhone</td>
<td class="fromtable">#p.SizePhone</td>
<td class="fromtable">#p.PriceLight</td>
<td class="fromtabletime">#p.PriceOk</td>
<td class="totable">#p.PriceHigh</td>
</tr>
}
</table>
All data is generated from multiple linked tables.It is assumed that the user selects one of the "Price" and the form must pass the selected data and price in the Post request.
2)I did it like this
#using System.Linq;
#model List<Searchphone>
<h2 class="search1"></h2>
<form class="priceeconom1" method="post" asp-action="Index" asp-controller="Home">
#foreach (var p in Model)
<table>
{
<tr class="searchdata">
<td class="flight"><input type="text" name="#p.ColourPhone</td>
<td class="fromtable"><input type="text" name="#p.TypePhone</td>
<td class="fromtable"><input type="text" name="#p.SizePhone</td>
<td class="pricelight"><input type="radio" name="price"value="#p.PriceLight.ToString("")"/>#p.PriceLight.ToString("")</td>
<td class="fromtabletime"><input type="radio" name="price"value="#p.PriceOk.ToString("")/>#p.PriceOk.ToString("")</td>
<td class="totable"><input type="radio" name="price"value="#p.PriceHigh.ToString("")/>#p.PriceHigh.ToString("")</td>
<td class="button13"><button type="submit" asp-action="Buy" asp-route-id="#p.PhoneId" asp-controller="Home">Next</button></td>
</tr>
}
</table>
</form>
When I need to go to the next post-form. And I did the next view
#using System.Linq;
#using System;
#model List<Searchphone>
#{
ViewBag.Title = "PhoneId";
}
<h2 class="orderinformation">Order Data</h2>
<form method="post" class="formpass">
<input type="hidden" id="PhoneId"value="#ViewBag.PhoneId" name="PhoneId">
<label for="OrderSurName">Surname</label><br>
<input type="text" placeholder="Enter Surname" name="OrderSurName" required><br>
<label for="OrderName">Имя</label><br>
<input type="text" placeholder="Enter Name" name="OrderName" required><br>
<button type="submit" class="button7">To pay</button>
</form>
Controller
[HttpGet]
public IActionResult Buy(int? id)
{
if (id == null) return RedirectToAction("Index");
ViewBag.PhoneId = id;
return View();
}
[HttpPost]
public string Buy(Order order)
{
context.Orders.Add(order);
context.SaveChanges();
return "Thanks, " + order.OrderName;
}
But I have problem. I got URL:~/Home/Buy/0 and the view with return "Thanks, ". I don`t get the view for input Order Data. Table Order in Database gets default and null values. What is my mistake?
Part 2.Adding to the next question
Controller
[HttpGet]
public IActionResult Buy(int? id, string price)
{
if (id == null) return RedirectToAction("Index");
if(price=="PriceLight.ToString("")")
ViewBag.price=PriceLight.ToString("");
if(price=="PriceOk.ToString("")")
ViewBag.price=PriceOk.ToString("");
if(price=="PriceHigh.ToString("")")
ViewBag.price=PriceHigh.ToString("");
ViewBag.PhoneId = id;
return View();
}
View
#using System.Linq;
#using System;
#model List<Searchphone>
#{
ViewBag.Title = "PhoneId";
}
<h2 class="orderinformation">Order Data</h2>
<form method="post" class="formpass">
<h3> <input type="hidden" name="#ViewBag.price" value="#ViewBag.price" />#ViewBag.price</h3>
<br>
<input type="hidden" id="PhoneId"value="#ViewBag.PhoneId" name="PhoneId">
<label for="OrderSurName">Surname</label><br>
<input type="text" placeholder="Enter Surname" name="OrderSurName" required><br>
<label for="OrderName">Имя</label><br>
<input type="text" placeholder="Enter Name" name="OrderName" required><br>
<button type="submit" class="button7">To pay</button>
</form>
The form is submitted in post method while the return view action only accept a HttpGet request. So, it always hit the HttpPost action since they have the same name.
I tested your codes and find there are some problems in your first view.
[HttpGet]
public IActionResult Buy(int? id)
{
if (id == null) return RedirectToAction("Index");
ViewBag.PhoneId = id;
return View();
}
This action just receive a id parameter. There is no need to submit the whole form. In my opinion, You don’t even need to use forms, just use the < a > tag like below:
#using System.Linq;
#model List<Searchphone>
<h2 class="search1"></h2>
#foreach (var p in Model)
{
<table>
<tr class="searchdata">
<td class="flight"><input type="text" name="#p.ColourPhone" /></td>
<td class="fromtable"><input type="text" name="#p.TypePhone" /></td>
<td class="fromtable"><input type="text" name="#p.SizePhone" /></td>
<td class="pricelight"><input type="checkbox" name="#p.PriceLight.ToString()" /></td>
<td class="fromtabletime"><input type="checkbox" name="#p.PriceOk.ToString()" /></td>
<td class="totable"><input type="checkbox" name="#p.PriceHigh.ToString()" /></td>
<td class="totable"> <a asp-action="Buy" asp-route-id="#p.PhoneId" asp-controller="Home">Next</a></td>
</tr>
</table>
}

Dynamic Model Binding Partial View to Model MVC?

I'm trying to bind the model from the partial view to my main form. My Model workoutPlan only stores a list of WorkoutSets
public List<WorkoutSet> WorkoutSet;
In my main page. My form looks something like this:
#model WorkoutPlanObjects.WorkoutPlan
#using (Html.BeginForm("AddNewPlan", "Workout", FormMethod.Post))
{
if (Model != null)
{
<table id="workoutTable">
<tr>
<td>
#{Html.RenderPartial("~/Views/Partial/_AddNewPlan.cshtml", Model);}
</td>
</tr>
</table>
}
<input type="submit" id="submit" value="submit" />
}
and here's my partial view _AddNewPlan
#model WorkoutPlanObjects.WorkoutPlan
#if(Model!=null)
{
foreach (var item in Model.WorkoutSet)
{
#Html.TextBoxFor(a => item.Repeats)
}
}
I was able to update my partial view using ajax calls but when I try to submit the form, no values get passed. Here's the snippet of the code in chrome which shows the rendered partial view (excuse the formatting). Any solution for this?
I could see that the name of the rendered views are all the same item.Repeats. How should I change this partial view name to bind with the main page model?
<form action="/Workout/AddNewPlan" method="post">
<table id="workoutTable">
<tbody><tr>
<td>
<input id="item_Repeats" name="item.Repeats" type="text" value="1">
<input id="item_Repeats" name="item.Repeats" type="text" value="2">
<input id="item_Repeats" name="item.Repeats" type="text" value="3">
<input id="item_Repeats" name="item.Repeats" type="text" value="4">
</td>
</tr>
</tbody>
</table>
<input type="submit" id="submit" value="submit">
</form>
Change your foreach loop to a for loop so that the inputs are correctly named
foreach (iny i = 0; i < Model.WorkoutSet.Count; i++)
{
#Html.TextBoxFor(a => a.WorkoutSet[i].Repeats)
}
which will render
<input .... name="WorkoutSet[0].Repeats" type="text" value="1">
<input .... name="WorkoutSet[1].Repeats" type="text" value="2">
and allow the DefaultModelBinder to bind the collection.
Note property WorkoutSet will need to be IList. Alternatively you can create a custom EditorTemplate for WorkoutSet and use #Html.EditorFor(m => m.WorkoutSet)

How to update Partial View without full replacement

I have this partial view. This works, ie, when the user clicks the button, an ajax trip is made to the server, and it updates the partial view and it comes down and replaces the current div with the updated Div and shows the Promo Message.
However, it seems there should be a better way to do this. In other words, is it necessary to replace the entire partial view? Isn't there a way to send just the data up to the server, and then update just the message when it gets back, like maybe via a JSON call?
Controller:
public ActionResult ApplyPromoCode(OrderViewModel orderViewModel) {
orderViewModel.PromoMessage = "Promo has been applied";
return PartialView("PromoPartial", orderViewModel);
}
Partial View:
#model NTC.PropertySearch.Models.OrderViewModel
#using (Ajax.BeginForm("ApplyPromoCode", "OrderSummary", new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "promo" }))
{
<div id="promo">
<table>
<td>
#Html.LabelFor(m => m.PromoCode)
</td>
<td>
#Html.TextBoxFor(m => m.PromoCode)
</td>
<td>
#Html.ValidationMessageFor(m => m.PromoCode)
</td>
<td>
<input type="submit" value="Apply Promo Code" />
</td>
<td>
#Html.DisplayFor(m=> m.PromoMessage)
</td>
</table>
</div>
}
you can do this to
Controller
public ActionResult ApplyPromoCode(OrderViewModel orderViewModel) {
//your processing code
return Content("Promo has been applied");
}
View
#model NTC.PropertySearch.Models.OrderViewModel
#using (Ajax.BeginForm("ApplyPromoCode", "OrderSummary", new AjaxOptions { UpdateTargetId = "pcode" }))
{
<div id="promo">
<table>
<td>
#Html.LabelFor(m => m.PromoCode)
</td>
<td>
#Html.TextBoxFor(m => m.PromoCode)
</td>
<td>
#Html.ValidationMessageFor(m => m.PromoCode)
</td>
<td>
<input type="submit" value="Apply Promo Code" />
</td>
<td>
<div id="pcode"></div>
</td>
</table>
</div>
}
Instead of returning a PartialView you can always return a JSON object/array or some XML and use jQuery/JavaScript on your callback function to update the values of your input fields.
Here's an example of some code I use to return JSON from a Controller:
public ActionResult CurrentTags(int entityID)
{
Entity entity = db.Entity.Find(entityID);
var tags = from tag in entity.Tag
select new
{
id = tag.Name,
text = tag.Name
};
return this.Json(tags, JsonRequestBehavior.AllowGet);
}

MVC list of checkboxes check and select to Action then to csv file

I have a view like:
#model IEnumerable<VectorCheck.Models.Invoice>
#{
ViewBag.Title = "Exportable Invoices";
}
<script src="../../Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
<script src="../../Scripts/jquery-ui-1.8.16.min.js" type="text/javascript"></script>
<script src="../../Scripts/Views/Export/index.js" type="text/javascript"></script
<header class="header">
<div class="headerText">
<h1>Exportable Invoices</h1>
</div>
</header>
#using (Html.BeginForm("Export", "Export")) {
<table>
<tr class="mainheader">
<th>Invoice Number</th>
<th>Date</th>
<th>Organisation</th>
<th>Total (Excl GST)</th>
<th>Status</th>
<th>Exported Date</th>
<th>
<select id="expenseSelect"></select>
<input type="submit" id="btnexport" value="Export" />
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.InvoiceNumber)
</td>
<td>
#Html.DisplayFor(modelItem => item.InvoiceDate, "{0:D}")
</td>
<td>
#Html.DisplayFor(modelItem => item.Organisation.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.TotalExcludingGst)
</td>
<td>
#Html.DisplayFor(modelItem => item.Status)
</td>
<td>
#Html.DisplayFor(modelItem => item.ExportedDateTime)
</td>
<td class="centered">
<input type="checkbox" class="exportcheckbox" data-invoiceid=#item.InvoiceId />
</td>
</tr>
}
</table>
}
<div>
#Html.ActionLink("Back to Summary", "Index", "Invoice")
</div>
Ok, so see how each checkbox has an attribrute data-invoiceid=#item.InvoiceId. Well I'm trying to get to an action method the Ids of all the invoices that have had their checkboxes checked. Also I'm trying to get the id of the selectlist expenseSelect which has options added to it on page load via jquery. I managed to achieve this with jquery and then sending the data with a $.post. The problem is in the file I'm sending the info to:
public ActionResult Export()
{
...
var csvData = _utility.GetCsvData(data);
return File(Encoding.UTF8.GetBytes(csvData), "text.csv", "invoices.csv");
}
brings up a save/open file dialog. I'm been informed this won't work for the jquery ajax call and I need to post the info back using a submit.
That's fine but now I have no idea how to send the select id and a list of the ids of the checked checkboxes to the method. Can anybody show me how to go about this?
You don't need any HTML5 data-* attributes since they are not sent to the server when you submit the form. In order to send their values you will have to use AJAX but this won't work with file downloads. So simply give your checkboxes a name:
<td class="centered">
<input type="checkbox" class="exportcheckbox" name="ids" value="#item.InvoiceId" />
</td>
and then on the server the default model binder will automatically construct an array of the ids of the checked items:
[HttpPost]
public ActionResult Export(int[] ids)
{
byte[] data = ...
return File(data, "text/csv", "invoices.csv");
}
Depending on the type of InvoiceId you might need to adjust the type of the action argument.
Radically changing my answer...
You could dynamically add a hidden IFRAME to your page. The IFRAME src can take your selected "ids" as a querystring parameter. This should get your your download dialog.
Got some help with the jquery from here: JQuery: Turn array input values into a string optimization
var selectedIdsArray = $(":checked").map(function(){return $(this).attr('data-invoiceid');});
var url = '#Url.Action("Export", "Export")?csv=' selectedIdsArray.get().join(',');
$('body').append("<iframe style='visibility:hidden' src='"+url +"'/>");

binding asp.net mvc form element to complex object for posting to controller

I am trying to refactor to avoid parsing the FormCollection from the view so i changed this to pass in an strongly typed object. My form elements are the same names as the properties on the LinkUpdater Object. But when i put a breakpoint on the first link in the controller all of the properties are null.
any ideas or suggestions?
View:
<%using (Ajax.BeginForm("AddNewLink", "Links", new AjaxOptions { UpdateTargetId = "LinkList", LoadingElementId = "updating", OnSuccess = "done" }))
{ %>
<fieldset style="text-align:left">
<table>
<tr><td>Url:</td><td> <input style="width:500px" type="text" name="URL" /></td></tr>
<tr><td>Description: </td><td><input style="width:400px" type="text" name="Description" /></td></tr>
<tr><td>Tags: </td><td><input style="width:400px" id="Tags" name="tags" type="text" /></td></tr>
<tr><td><input type="submit" value="Add Link" name="submit" /></td></tr>
</table>
</fieldset>
<% } %>
Controller Post:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddNewLink(LinkUpdater linkUpdater_)
{
string[] tags = linkUpdater_.Tags.Replace(" ", "").Split(',');
linkRepository.AddLink(linkUpdater_.URL, linkUpdater_.Description, tags);
.....
}
LinkUpdater class:
public class LinkUpdater
{
public string URL;
public string Description;
public string Tags;
}
Model binder in MVC binds to properties, while you use fields. Change to
public string URL { get; set; }
And by the way, there're other drawbacks, like if you use private set, it will silently skip binding, too.
Is there any particular reason your are not using the strongly-typed HTMLHelpers to render your input fields?
<%using (Ajax.BeginForm("AddNewLink", "Links", new AjaxOptions { UpdateTargetId = "LinkList", LoadingElementId = "updating", OnSuccess = "done" }))
{ %>
<fieldset style="text-align: left">
<table>
<tr>
<td>
Url:
</td>
<td>
<%=Html.TextBox("URL", Model.URL, new { style = "width:500px;" }) %>
</td>
</tr>
<tr>
<td>
Description:
</td>
<td>
<%=Html.TextBox("Description", Model.Description, new { style = "width:400px;" }) %>
</td>
</tr>
<tr>
<td>
Tags:
</td>
<td>
<%=Html.TextBox("Tags", Model.Tags, new { style = "width:400px;" }) %>
</td>
</tr>
<tr>
<td>
<input type="submit" value="Add Link" name="submit" />
</td>
</tr>
</table>
</fieldset>
<% } %>
I'm not sure it will fix your problem, but it's a step in the right direction at least.

Resources