IList binding Razor Pages - c#

Trying to bind IList so that I can update the fields that I have. However, ending up with an empty list with OnPostAsync. Not sure what I'm missing.
My code looks as follows:
[BindProperty]
public IList<Runbook_Serverlist_Plus> RunbookServerListPlus { get; set; }
This list is filled with the OnGetAsync function using the below code:
public async Task OnGetAsync()
{
var listRunbookServerList = await _context.Runbook_Serverlist.ToListAsync();
RunbookServerListPlus = listRunbookServerList.Select(item => new Runbook_Serverlist_Plus(item)).ToList();
}
So from my model I first get the IList<Runbook_Serverlist> and then I create a new list for Runbook_Serverlist_Plus.
Idea is to have a sort of a base class of Runbook_Serverlist, then put a Runbook_Serverlist_Plus on top, in which I can set specific fields which I can later use to update some fields.
See code below:
public class Runbook_Serverlist_Plus
{
[BindProperty]
public Runbook_Serverlist Bc {get; set; }
public Runbook_Serverlist_Plus(Runbook_Serverlist bsBc)
{
Bc = bsBc;
CheckCompleted = false;
}
public bool CheckCompleted { get; set; }
}
In my cshmtl the code is as follows:
<form method="post">
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.Servername)
</th>
<th>
#Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.Status)
</th>
<th>
#Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.Cluster)
</th>
<th>
#Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.StatusChange)
</th>
<th>
#Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.PreRun)
</th>
<th>
#Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.Ordering)
</th>
<th></th>
</tr>
</thead>
<tbody>
#for (var i = 0; i < Model.RunbookServerListPlus.Count; i++)
{
var item = Model.RunbookServerListPlus[i];
<tr>
<td>
#Html.DisplayFor(modelItem => item.Bc.Servername)
</td>
<td>
#Html.DisplayFor(modelItem => item.Bc.Status)
</td>
<td>
#Html.DisplayFor(modelItem => item.Bc.Cluster)
</td>
<td>
#Html.DisplayFor(modelItem => item.Bc.StatusChange)
</td>
<td>
#Html.DisplayFor(modelItem => item.Bc.PreRun)
</td>
<td>
#Html.DisplayFor(modelItem => item.Bc.Ordering)
</td>
<td>
<input hidden asp-for="#item.Bc.Servername" class="form-control" />
<input asp-for="#item.CheckCompleted" class="form-control"/>
</td>
</tr>
}
</tbody>
</table>
<div class="form-group">
<input type="submit" value="Update" class="btn btn-primary" />
</div>
</form>
So I have a checkbox for the CheckCompleted item and when doing a post, I would like to see all the checkboxes which are marked.
When I do a submit/post, I would expect the RunbookServerListPlus to be filled. However, this one is empty all the time.
What am I missing?
Post function is for now nothing else then:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
return RedirectToPage("./Index");
}

Firstly,you can add hidden inputs to bind model data,form post will pass inputs' value.And .net core bind model with name attribute.If you want to bind data with list,you need to set name as list[index].xxx.
And If you only want to pass Runbook_Serverlist_Plus when CheckCompleted is checked,you can use js to change the name of hidden inputs to right format before form post.Here is a demo.
Models:
public class Runbook_Serverlist_Plus
{
[BindProperty]
public Runbook_Serverlist Bc { get; set; }
public Runbook_Serverlist_Plus(Runbook_Serverlist bsBc)
{
Bc = bsBc;
CheckCompleted = false;
}
public Runbook_Serverlist_Plus()
{
}
public bool CheckCompleted { get; set; }
}
public class Runbook_Serverlist
{
public string Servername { get; set; }
public string Status { get; set; }
public string Cluster { get; set; }
public string StatusChange { get; set; }
public string PreRun { get; set; }
public string Ordering { get; set; }
}
cshtml:
<form method="post">
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.Servername)
</th>
<th>
#Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.Status)
</th>
<th>
#Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.Cluster)
</th>
<th>
#Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.StatusChange)
</th>
<th>
#Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.PreRun)
</th>
<th>
#Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.Ordering)
</th>
<th></th>
</tr>
</thead>
<tbody>
#for (var i = 0; i < Model.RunbookServerListPlus.Count; i++)
{
var item = Model.RunbookServerListPlus[i];
<tr>
<td>
#Html.DisplayFor(modelItem => item.Bc.Servername)
</td>
<td>
#Html.DisplayFor(modelItem => item.Bc.Status)
</td>
<td>
#Html.DisplayFor(modelItem => item.Bc.Cluster)
</td>
<td>
#Html.DisplayFor(modelItem => item.Bc.StatusChange)
</td>
<td>
#Html.DisplayFor(modelItem => item.Bc.PreRun)
</td>
<td>
#Html.DisplayFor(modelItem => item.Bc.Ordering)
</td>
<td>
<input asp-for="#item.CheckCompleted" class="form-control" name="RunbookServerListPlus[index].CheckCompleted" />
<input hidden asp-for="#item.Bc.Servername" class="form-control" name="RunbookServerListPlus[index].Bc.Servername" />
<input hidden asp-for="#item.Bc.Status" class="form-control" name="RunbookServerListPlus[index].Bc.Status" />
<input hidden asp-for="#item.Bc.Cluster" class="form-control" name="RunbookServerListPlus[index].Bc.Cluster" />
<input hidden asp-for="#item.Bc.StatusChange" class="form-control" name="RunbookServerListPlus[index].Bc.StatusChange" />
<input hidden asp-for="#item.Bc.PreRun" class="form-control" name="RunbookServerListPlus[index].Bc.PreRun" />
<input hidden asp-for="#item.Bc.Ordering" class="form-control" name="RunbookServerListPlus[index].Bc.Ordering" />
</td>
</tr>
}
</tbody>
</table>
<div class="form-group">
<input type="submit" value="Update" class="btn btn-primary" />
</div>
</form>
<script>
$("form").submit(function () {
var index = 0;
$("tbody tr").each(function () {
var lasttd = $(this).find('td:last-child');
if (lasttd.find("input")[0].checked) {
lasttd.find("input").each(function () {
$(this).attr("name", $(this).attr("name").replace("index",index));
})
index++;
}
})
})
</script>
cshtml.cs(I use fake data to test):
[BindProperty]
public List<Runbook_Serverlist_Plus> RunbookServerListPlus { get; set; }
public void OnGet()
{
RunbookServerListPlus = new List<Runbook_Serverlist_Plus> {
new Runbook_Serverlist_Plus { Bc = new Runbook_Serverlist { Cluster = "c1", Ordering = "1", PreRun="p1", Servername="sname1", Status="status1", StatusChange="statuschange1" } },
new Runbook_Serverlist_Plus { Bc = new Runbook_Serverlist { Cluster = "c2", Ordering = "2", PreRun="p2", Servername="sname2", Status="status2", StatusChange="statuschange2" } },
new Runbook_Serverlist_Plus { Bc = new Runbook_Serverlist { Cluster = "c3", Ordering = "3", PreRun="p3", Servername="sname3", Status="status3", StatusChange="statuschange3" } }
};
}
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
return RedirectToPage("./Index");
}
result:
Update(Pass a whole list):
Firstly,remove js in the first demo.
And then change td like this:
<td>
<input asp-for="#item.CheckCompleted" class="form-control" name="RunbookServerListPlus[#i].CheckCompleted" />
<input hidden asp-for="#item.Bc.Servername" class="form-control" name="RunbookServerListPlus[#i].Bc.Servername" />
<input hidden asp-for="#item.Bc.Status" class="form-control" name="RunbookServerListPlus[#i].Bc.Status" />
<input hidden asp-for="#item.Bc.Cluster" class="form-control" name="RunbookServerListPlus[#i].Bc.Cluster" />
<input hidden asp-for="#item.Bc.StatusChange" class="form-control" name="RunbookServerListPlus[#i].Bc.StatusChange" />
<input hidden asp-for="#item.Bc.PreRun" class="form-control" name="RunbookServerListPlus[#i].Bc.PreRun" />
<input hidden asp-for="#item.Bc.Ordering" class="form-control" name="RunbookServerListPlus[#i].Bc.Ordering" />
</td>
result:
Check data passed to handler:

Only one of the handlers fires on each request, depending on the HTTP verb that was used to make the request. OnGet is executed when the page is requested using HTTP Get method. OnPost is executed by the POST method.
The web is stateless. That means that variables initialised on one request are not available to another request. If you want to work with the collection in the OnPost method, you need to instantiate it again in the OnPost handler.
More details on my site here: https://www.learnrazorpages.com/razor-pages/handler-methods

Related

Getting the id of a table row and passing it to a event handler when a checkbox is checked

This question was posted almost eight years ago, (Question 16853364). When I follow the answer that was provided the code runs but the the value of the record Id is not past to the event handler. I'm using ASP.NET Core 3.1 creating a Razor Page application. I assume the original question was based on using ASP.NET 2.x and MVC, Hopefully that is why it is not working for me.
The Index page is a list to task that a user has been assigned. I've added a checkbox to the page; after completing the user checks the checkbox. Checking the box should trigger an event handler that will update a column (tinyInt) in the database. Checking the checkbox does call the event handler, however the code that should get the record's Id before call the handler does not get the Id. My code on the Index.cshtml that displays the records and calls the handler is:
...
#if (Model.ScheduleOut.Count() == 0)
{
<p>
This speaker has not been scheduled in the past six weeks or in the next 6 months...
</p>
}
else
{
<table class="table table-striped border" height="40">
<tr class="table-secondary">
<th>
#Html.LabelFor(m => m.SchedOutgoingVM.ScheduleOutObj, "Id:")
</th>
<th>
#Html.LabelFor(m => m.SchedOutgoingVM.ScheduleOutObj, "DOT:")
</th>
<th>
#Html.LabelFor(m => m.SchedOutgoingVM.ScheduleOutObj, "Talk #'s:")
</th>
<th>
#Html.DisplayNameFor(m => m.SchedOutgoingVM.CongObj.CongName)
</th>
<th>
#Html.LabelFor(m => m.SchedOutgoingVM, "Date / Time:")
</th>
<th>
#Html.LabelFor(m => m.SchedOutgoingVM, "Talk Coordinator:")
</th>
<th>
#Html.LabelFor(m => m.SchedOutgoingVM, "TC's Phone:")
</th>
<th></th>
<th></th>
</tr>
<!-- *************** display records ***************-->
#foreach (var item in Model.ScheduleOut)
{
<tr id="1">
<td class="tdBorder">
#Html.DisplayFor(m => item.Id)
</td>
<td>
#Html.DisplayFor(m => item.DOT)
</td>
<td>
#Html.DisplayFor(m => item.SpkTalkNum)
</td>
<td>
#Html.DisplayFor(m => item.Congregation.CongName)
</td>
<td>
#Html.DisplayFor(m => item.Congregation.MtgDay) / #Html.DisplayFor(m => item.Congregation.MtgTime)
</td>
<td>
#Html.DisplayFor(m => item.Congregation.tcFirstName) #Html.DisplayFor(m => item.Congregation.tcLastName)
</td>
<td>
#Html.DisplayFor(m => item.Congregation.tcMobilePhone)
</td>
<td>
<!-- check or uncheck checkbox based on value in database -->
#if (item.Accepted == null || item.Accepted == 0)
{
<!-- if false in the database-->
<input asp-for="AcceptedBoolean" type="checkbox" onclick="ckBox(this)" form-check-input">
}
else
{
<!-- if true in the database-->
<input asp-for="AcceptedBoolean" type="checkbox" checked="checked" onclick="ckBox(this)" form-check-input">
}
</td>
</tr>
}
</table>
}
...
The Index.cshtml.cs
...
//********** OnPost - update Accepted (tinyInt)column in database (using id) **********
public async Task<JsonResult> OnGetUpDateAccepted(int id)
{
///code to update database
return new JsonResult(id);
}
...
Any suggestion on what I'm doing wrong or missing is greatly appreciated. If you have a better way of updating the database I would like to know that also.
Javascript Code:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
function ckBox(e) {
if (e.checked) {
////var Testt = $(this).closest('tr').attr('Testtid');
////alert('Got this far...')
var id = $(this).closest('tr').attr('id');
console.log(Testt); //used to capture the value at this point
alert(id);
$.getJSON('?handler=UpDateAccepted&Testt=' + id, (data) => {
});
} else {
var Testt = 0
alert('bye');
$.getJSON('?handler=UpDateAccepted&Testt=' + id, (data) => {
});
}
}
</script>
Firstly,you comment on some js code when you debug the code,and this caused the js in a mess.The variable name is not correct in your sample.Be careful with theses variables.
Then,the backend paramater named id,so the request url should be:'?handler=UpDateAccepted&id=' + id instead of
'?handler=UpDateAccepted&Testt=' + id.
Finally,you want to pass the id of the record,but all of the tr have the same id.You need change <tr id="1"> to:<tr id="#item.Id">.
Here is my whole working demo:
Model:
public class ScheduleOut
{
public int Id { get; set; }
public string DOT { get; set; }
public string SpkTalkNum { get; set; }
public int? Accepted { get; set; }
public Congregation Congregation { get; set; }
}
public class Congregation
{
public string CongName { get; set; }
public string MtgTime { get; set; }
public string tcFirstName { get; set; }
public string tcLastName { get; set; }
public string tcMobilePhone { get; set; }
public int MtgDay { get; set; }
}
public class SchedOutgoingVM
{
public ScheduleOut ScheduleOutObj { get; set; }
public Congregation CongObj { get; set; }
}
Index.cshtml:
#page
#model IndexModel
#if (Model.ScheduleOut.Count() == 0)
{
<p>
This speaker has not been scheduled in the past six weeks or in the next 6 months...
</p>
}
else
{
<table class="table table-striped border" height="40">
<tr class="table-secondary">
<th>
#Html.LabelFor(m => m.SchedOutgoingVM.ScheduleOutObj, "Id:")
</th>
<th>
#Html.LabelFor(m => m.SchedOutgoingVM.ScheduleOutObj, "DOT:")
</th>
<th>
#Html.LabelFor(m => m.SchedOutgoingVM.ScheduleOutObj, "Talk #'s:")
</th>
//...
<th>
#Html.LabelFor(m => m.SchedOutgoingVM, "TC's Phone:")
</th>
<th></th>
<th></th>
</tr>
#foreach (var item in Model.ScheduleOut)
{
<!-- *************** change here ***************-->
<tr id="#item.Id">
<td class="tdBorder">
#Html.DisplayFor(m => item.Id)
</td>
<td>
#Html.DisplayFor(m => item.DOT)
</td>
<td>
#Html.DisplayFor(m => item.SpkTalkNum)
</td>
<td>
#Html.DisplayFor(m => item.Congregation.CongName)
</td>
<td>
#Html.DisplayFor(m => item.Congregation.MtgDay) / #Html.DisplayFor(m => item.Congregation.MtgTime)
</td>
<td>
#Html.DisplayFor(m => item.Congregation.tcFirstName) #Html.DisplayFor(m => item.Congregation.tcLastName)
</td>
<td>
#Html.DisplayFor(m => item.Congregation.tcMobilePhone)
</td>
<td>
#if (item.Accepted == null || item.Accepted == 0)
{
<input asp-for="AcceptedBoolean" type="checkbox" onclick="ckBox(this)" form-check-input">
}
else
{
<input asp-for="AcceptedBoolean" type="checkbox" checked="checked" onclick="ckBox(this)" form-check-input">
}
</td>
</tr>
}
</table>
}
JS in Index.cshtml:
#section Scripts
{
<script type="text/javascript">
function ckBox(e) {
if (e.checked) {
var id = $(e).closest('tr').attr('id');
$.getJSON('?handler=UpDateAccepted&id=' + id, (data) => {
});
} else {
//do your stuff...
}
}
</script>
}
Result:
BTW,if User unchecked the checkbox,it seems also need to get the id to update.If what I guess is correct,you need change like below:
<script type="text/javascript">
function ckBox(e) {
var id = $(e).closest('tr').attr('id');
$.getJSON('?handler=UpDateAccepted&id=' + id, (data) => {
});
}
</script>

Why does my page refresh when I click the filter button in my view?

I am trying to build a filter with a razor page to filter optionally off of user input on a search box and a drop-down. In other words, they can filter off either, both or not at all.
I followed this tutorial here, and was able to have everything work correctly, but when I tried to do the same thing but with my own data and my own application for more practice, it did not work. I am not aware of anything different.
https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/search?view=aspnetcore-2.2
//Controller Method
public async Task<IActionResult> Index(string travels, string
searchString)
{
IQueryable<string> travelQuery = from c in _context.CardInfo
orderby c.Travels
select c.Travels;
var cards = from c in _context.CardInfo
select c;
if (!String.IsNullOrEmpty(searchString))
{
cards = cards.Where(c => c.CardName.Contains(searchString));
}
if (!string.IsNullOrEmpty(travels))
{
cards = cards.Where(x => x.Travels == travels);
}
var cardInfoVM = new CardInfoViewModel
{
Travels = new SelectList(await
travelQuery.Distinct().ToListAsync()),
CardInfos = await cards.ToListAsync()
};
return View(cardInfoVM);
}
//Model
public class CardInfo
{
public int Id { get; set; }
public int CardId { get; set; }
public string CardName { get; set; }
public int Elixir { get; set; }
public string CardType { get; set; }
public string Travels { get; set; }
public string Targets { get; set; }
public string AttackAir { get; set; }
public string Spawner { get; set; }
public int RangeLevel { get; set; }
}
//ViewModel
public class CardInfoViewModel
{
public List<CardInfo> CardInfos { get; set; }
public SelectList Travels { get; set; }
public string CardTravel { get; set; }
public string SearchString { get; set; }
}
//cshtml view
#model ClashMVC.Models.CardInfoViewModel
#{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-controller="CardInfo" asp-action="Index" method="get">
<p>
<select asp-for="CardTravel" asp-items="Model.Travels">
<option value="">All</option>
</select>
Title: <input type="text" name="SearchString">
<input type="submit" value="Filter" />
</p>
</form>
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.CardInfos[0].CardId)
</th>
<th>
#Html.DisplayNameFor(model => model.CardInfos[0].CardName)
</th>
<th>
#Html.DisplayNameFor(model => model.CardInfos[0].Elixir)
</th>
<th>
#Html.DisplayNameFor(model => model.CardInfos[0].CardType)
</th>
<th>
#Html.DisplayNameFor(model => model.CardInfos[0].Travels)
</th>
<th>
#Html.DisplayNameFor(model => model.CardInfos[0].Targets)
</th>
<th>
#Html.DisplayNameFor(model => model.CardInfos[0].AttackAir)
</th>
<th>
#Html.DisplayNameFor(model => model.CardInfos[0].Spawner)
</th>
<th>
#Html.DisplayNameFor(model => model.CardInfos[0].RangeLevel)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.CardInfos)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.CardId)
</td>
<td>
#Html.DisplayFor(modelItem => item.CardName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Elixir)
</td>
<td>
#Html.DisplayFor(modelItem => item.CardType)
</td>
<td>
#Html.DisplayFor(modelItem => item.Travels)
</td>
<td>
#Html.DisplayFor(modelItem => item.Targets)
</td>
<td>
#Html.DisplayFor(modelItem => item.AttackAir)
</td>
<td>
#Html.DisplayFor(modelItem => item.Spawner)
</td>
<td>
#Html.DisplayFor(modelItem => item.RangeLevel)
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.Id">Edit</a> |
<a asp-action="Details" asp-route-
id="#item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="#item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
There is no error message. I see the expected query string parameters in the browser, but when I try to apply a filter based off of the dropdown (CardTravel) the page reloads and the filter is not applied.
In the Controller Index method parameter
string travels
needs to match the View's
select asp-for="CardTravel"
For sure the <input type="submit" value="Filter" /> will cause the page reload because of you have an input/button with type="submit" inside the form. If you don't want to refresh the page after clicked, please use JS/Jquery (or anything else) to make an async call to Controller

Why parameter of the action method is null when view is posted?

This is an ASP.NET MVC project. I have a view that displays a collection of BookRentViewModel items.
When I click on the button in the view, the view is posted to an action method called rent. rent action method has a parameter called items of type IEnumerable<BookRentViewModel>.
Here is the code of the view:
#model IEnumerable<DaramSerl.Models.ViewModels.BookRentViewModel>
#using (Html.BeginForm("rent", "RentBook", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.bookName)
</th>
<th>
#Html.DisplayNameFor(model => model.isRented)
</th>
<th>
#Html.DisplayNameFor(model => model.startDate)
</th>
<th>
#Html.DisplayNameFor(model => model.endDate)
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.EditorFor(modelItem => item.bookName)
</td>
<td>
#Html.EditorFor(modelItem => item.isRented)
</td>
<td>
#Html.EditorFor(modelItem => item.startDate)
</td>
<td>
#Html.EditorFor(modelItem => item.endDate)
</td>
</tr>
}
</table>
<input type="submit" value="Create" class="btn btn-primary" />
}
And here is the action method:
[HttpPost]
public async Task<ActionResult> rent(IEnumerable<BookRentViewModel> items)
{
if (ModelState.IsValid)
{
return RedirectToAction("/Index");
}
return View();
}
And here is the BookRentViewModel:
public class BookRentViewModel
{
[Key]
public int bookId{ get; set; }
public string bookName { get; set; }
public bool isRented { get; set; }
public DateTime startDate { get; set; }
public DateTime endDate { get; set; }
}
The problem is that items parameter is always null when rent action is triggered.
Any idea why items is null and does not get the collection from the view?
UPDATE
I used fiddler to see if the collection is posted to the server but it seems it cannot be parsed into BookRentViewModel items.
UPDATE3
Here is screenshot from fiddler with the collection sent from the view:
Doesnt look like you're setting a value for public int bookId - if thats the case this will fail validation as its a non-nullable type.
Either way, set a breakpoint in your controller method and check the errors on ModelState - see Get error message if ModelState.IsValid fails?
Edit
To include properties but not show them on your view, use the hidden field razor tag helper:
#Html.HiddenFor(x => x.bookId)
I tried reproduce source code.
You can change model mapping in cshtml file as below
#for (int i = 0; i < Model.Count();i++ )
{
<tr>
<td>#Html.TextBox("items[" + #i + "].bookName",
Model.ElementAt(i).bookName
)</td>
<td>#Html.CheckBox("items[" + #i + "].isRented",
Model.ElementAt(i).isRented
)</td>
<td>#Html.TextBox("items[" + #i + "].startDate",
Model.ElementAt(i).startDate
)</td>
<td>#Html.TextBox("items[" + #i + "].endDate",
Model.ElementAt(i).endDate
)</td>
</tr>
}
rent.cshtml file
#model IEnumerable<WebApplication2.Controllers.BookRentViewModel>
#using (Html.BeginForm("rent", "Rent", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.bookName)
</th>
<th>
#Html.DisplayNameFor(model => model.isRented)
</th>
<th>
#Html.DisplayNameFor(model => model.startDate)
</th>
<th>
#Html.DisplayNameFor(model => model.endDate)
</th>
</tr>
#*#foreach (var item in Model)
{
<tr>
<td>
#Html.EditorFor(modelItem => item.bookName)
</td>
<td>
#Html.EditorFor(modelItem => item.isRented)
</td>
<td>
#Html.EditorFor(modelItem => item.startDate)
</td>
<td>
#Html.EditorFor(modelItem => item.endDate)
</td>
</tr>
}*#
#for (int i = 0; i < Model.Count();i++ )
{
<tr>
<td>#Html.TextBox("items[" + #i + "].bookName",
Model.ElementAt(i).bookName
)</td>
<td>#Html.CheckBox("items[" + #i + "].isRented",
Model.ElementAt(i).isRented
)</td>
<td>#Html.TextBox("items[" + #i + "].startDate",
Model.ElementAt(i).startDate
)</td>
<td>#Html.TextBox("items[" + #i + "].endDate",
Model.ElementAt(i).endDate
)</td>
</tr>
}
</table>
<input type="submit" value="Create" class="btn btn-primary" />
}

Update mutiple records in database MVC 5 EF

Good evening,
Now I'll describe my situation:
Here is my Model:
[Table("Items")]
public class Item
{
[Key]
public string Id { get; set; }
public DateTime Generated { get; set; }
public string Content { get; set; }
public string UrlSeo { get; set; }
public bool IsActive { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
}
I;m implementing CRUD operations to DB records, but I need implement one more Action, I need to Update for example UrlSeo property in selected records in one action.
So here is my view:
#model IEnumerable<CheckBoxes.Models.Item>
#{
ViewBag.Title = "Items";
}
<dv class="page-header">
<h3>Items</h3>
</dv>
<p>
#Html.ActionLink("Create New", "Create")
</p>
#using (Html.BeginForm("ChangeUrl", "Items", FormMethod.Post))
{
<div class="row">
<div class="form-group-sm">
<div class="col-md-4">
#Html.TextBox("urlSeo", null, new { #class = "form-control" })
</div>
<div class="col-md-offset-2 col-md-4">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
<p>
</p>
</div>
<table class="table">
<tr>
<th>
<input type="checkbox" id="checkAll" />
</th>
<th>
#Html.DisplayNameFor(model => model.Generated)
</th>
<th>
#Html.DisplayNameFor(model => model.Content)
</th>
<th>
#Html.DisplayNameFor(model => model.UrlSeo)
</th>
<th>
#Html.DisplayNameFor(model => model.IsActive)
</th>
<th>
#Html.DisplayNameFor(model => model.Quantity)
</th>
<th>
#Html.DisplayNameFor(model => model.Price)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<th>
<input type="checkbox" class="checkBox" value="#item.Id" />
</th>
<td>
#Html.DisplayFor(modelItem => item.Generated)
</td>
<td>
#Html.DisplayFor(modelItem => item.Content)
</td>
<td>
#Html.DisplayFor(modelItem => item.UrlSeo)
</td>
<td>
#Html.DisplayFor(modelItem => item.IsActive)
</td>
<td>
#Html.DisplayFor(modelItem => item.Quantity)
</td>
<td>
#Html.DisplayFor(modelItem => item.Price)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
#Html.ActionLink("Details", "Details", new { id = item.Id }) |
#Html.ActionLink("Delete", "Delete", new { id = item.Id })
</td>
</tr>
}
</table>
}
#section Scripts{
#Scripts.Render("~/bundles/toastr")
<!--მასიური წაშლა-->
<script>
$(document).ready(function () {
$("#checkAll").click(function () {
$(".checkBox").prop('checked',
$(this).prop('checked'));
});
});
</script>
}
And Finally My Controller:
[HttpPost]
public async Task<ActionResult> ChangeUrl(string urlSeo, string[] id)
{
foreach (var itemId in id)
{
Item item = await db.Items.FindAsync(itemId);
item.UrlSeo = urlSeo;
db.Entry(item).State = EntityState.Modified;
db.Entry(item).Property(x => x.Generated).IsModified = false;
db.Entry(item).Property(x => x.Content).IsModified = false;
db.Entry(item).Property(x => x.IsActive).IsModified = false;
db.Entry(item).Property(x => x.Price).IsModified = false;
db.Entry(item).Property(x => x.Quantity).IsModified = false;
}
await db.SaveChangesAsync();
return Json(new { success = true });
}
Now Question
How to pass all checked items to controller and input from field.
I home someone will help me.
Where was problem in view here is necessary give name for checkbox, witch equals part of controller.
#foreach (var item in Model)
{
<tr>
<th>
<input type="checkbox" class="checkBox" value="#item.Id" name="id" />
</th>
Everything worked fine, yes one more thing, better to use:
return RedirectToAction("Index");
So this is working solution.

How to pass argument to ASP.NET MVC 3 controller that is called via onclick attribute of a html button?

I have the following View code (ASP:NET MVC 3):
#using(Html.BeginForm()){
#Html.ValidationSummary(true)
<table>
<tr>
<th>
City
</th>
<th>
Hotel
</th>
<th>
Room name
</th>
<th>
Number of beds
</th>
<th>
Price per night
</th>
<th></th>
</tr>
<tr>
<td>
#Html.DisplayFor(x=>Model.SelectedRoom.Hotel.City.Name)
</td>
<td>
#Html.DisplayFor(x => Model.SelectedRoom.Hotel.Name)
</td>
<td>
#Html.DisplayFor(x => Model.SelectedRoom.Name)
</td>
<td>
#Html.DisplayFor(x => Model.SelectedRoom.NumberOfBeds)
</td>
<td>
#Html.DisplayFor(x => Model.SelectedRoom.PricePerNight)
</td>
</tr>
</table>
<input type="hidden" name="RoomID" value="#Model.SelectedRoom.RoomID" id="RoomID" />
<br />
<br />
<p>
From: #Html.TextBoxFor(m=>m.DateOne, new {#class="datepicker1", #readonly="readonly" })
#Html.ValidationMessageFor(m=>m.DateOne)
To: #Html.TextBoxFor(m => m.DateTwo, new { #class = "datepicker2", #readonly = "readonly" })
#Html.ValidationMessageFor(m=>m.DateTwo)
</p>
<p>
Total cost : #Html.TextBoxFor(m=>m.TotalCost, new {#class="TotalAmount", #readonly="readonly" })
</p>
<br />
<input type="button" id="Reserve" value="Confirm" onclick = "window.location.href='/Home/MakeReservation'+#Model" />
}
Here is my Model definition for this View:
public class MakeReservationViewModel
{
BusinessLogic bl;
public MakeReservationViewModel()
{
bl = new BusinessLogic();
}
public Room SelectedRoom { get; set; }
[Required(ErrorMessage="Please select a starting date")]
public DateTime DateOne { get; set; }
[Required(ErrorMessage = "Please select an ending date")]
public DateTime DateTwo { get; set; }
public decimal TotalCost { get; set; }
}
How to call *MakeReservation controller action from above View by clicking on a button and setting it's onclick attribut to MakeReservation properly?*
Here is my Controller:
[HttpPost]
public ViewResult MakeReservation(MakeReservationViewModel mrvm)
{
if (ModelState.IsValid)
{
}
return View();
}
This is the error I ger:
Object reference not set to an instance of an object.
on this line:
How to make model accept hidden field?
SOLVED.
I added :
#Html.TextBoxFor(m => m.SelectedRoom.RoomID, new {#class="RoomID", #hidden="hidden" })
instead of previous way that used not strongly typed property.

Categories

Resources