MVC: Create does not work without #Html.EditorFor - c#

I am currently trying to learn something about MVC by creating a small project. I already have managed to get a lot of things working, but now I am facing something I can not explain.
Basically, I have the usual setup (Model, Viewer, Controller) and my Model database is displayed in a View. Starting with the standard Create-View and -Action, which can be generated automatically in Visual Studio, I intended to change this method, so that some cells have calculated values and do not come from a user input.
This works fine for my Ready-column and Ready-Date-column, but fails for the Month-column. To generate a new row somehow
#Html.EditorFor(model => model.Month)
is needed. If I remove this (like I did for Ready and Ready-Date) clicking the submit-Button doesn't create anything and the application stays on the Create-Page.
My two ActionResults in the ModelController look like this:
public ActionResult Create()
{
//I use this in order to print the UpcomingMonth on the Create-Page
ViewBag.upcomingMonth = getUpcomingMonth();
return View();
}
public ActionResult Create([Bind(Include = "Report_ID,Month,Ready,Ready_Date")] Report report)
{
if (ModelState.IsValid)
{
//I would like to use this calculation for the Month-Value
report.Month = getUpcomingMonth();
//For Ready and Ready_Date it works to set the values here before adding to the db
report.Ready = true;
report.Ready_Date = System.DateTime.Now;
db.Reports.Add(report);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(report);
}
And the relevant part of my View:
<p style="float:right">
#*Button to create new month*#
#Html.ActionLink("Create", "Create")
</p>
<h2>Latest</h2>
<table class="table">
<thead>
<tr>
#*Column-header: Month*#
<th style="width: 10%; text-align:center">
#Html.DisplayNameFor(model => model.Month)
</th>
#*Column-header: True/False is ready*#
<th style="width: 10%; text-align:center">
#Html.DisplayNameFor(model => model.Ready)
</th>
#*Column-header: Set ready Date*#
<th style="width: 20%; text-align:center">
#Html.DisplayNameFor(model => model.Ready_Date)
</th>
</tr>
</thead>
<tbody>
<tr>
#*Cell: Latest Month*#
<td style="width: 10%; text-align:center">
#Html.DisplayFor(modelItem => Model.ElementAt(0).Month)
</td>
#*Cell: Latest True/False is ready
<td style="width: 10%; text-align:center">
...
</td>
#*Cell: Latest Set ready Date*#
<td style="width: 20%; text-align:center">
#Html.DisplayFor(modelItem => Model.ElementAt(0).Ready_Date)
</td>
</tr>
</tbody>
</table>
I really would appreciate any help!
PS: With ValidationSummary I get the following (no error message):

I think your view model doesn't validate. You can see what's error if you add these lines to view.
#Html.ValidationSummary(true, "Errors:", new { #class = "text-danger bg-danger" })

I finally found out what caused this behaviour.
In the setup of my model I defined a validation requirement, which did not allow an empty string. Because I set my data after I had checked ModelState.IsValid, the empty String did not pass this check and therefore the row wasn't added.
I solved it by removing the validation requirements of Month.

Related

Item.Object.Property not showing in .htmlcs (#Html.DisplayFor)

I am currently working on a project where I want to show a column of a related record (form a sql database). For some of my table this works perfeclty fine, altough for one of them it does not. As shown below, there is no error and the record is filled in with the correct data, but it does not show up correclty. Can anyone help me with this? I tried updating my database already.
<table id="coaches">
<thead>
<tr>
<th>
</th>
<th>
#Html.DisplayNameFor(model => model.Picture)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model) {
<tr>
<td>
<img src=#Html.DisplayFor(modelItem => item.Picture) class="person">
</td>
<td>
<div style="padding-left:10px">
<div class="name">#Html.DisplayFor(modelItem => item.Organization.Name)Should be here</div>
<div class="natclub">
<img src="https://dalto.nl/wp-content/uploads/2018/08/dalto-logo.png" class="emblem">
<br>
<img src="https://cdn.countryflags.com/thumbs/netherlands/flag-400.png" class="flag">
</div>
</div>
</td>
</tr>
}
</tbody>
</table>
Organization Table
Coaches table
Page in question
Thanks in advance!
I tried to release a new update of the database using the PM Console, but nothing changed.

Index page with datatable took about 6-7 seconds before showing search box

I have a simple index page. When I load the page with only 500 records, the search box shows up straight away. But with 12k records, it take some time. Is there a way I can show a LOADING message, and after the search box is loaded, the LOADING message disappear.
This is the Index.cshtml
#model IEnumerable<BSMV2.Models.StoAppnOrgView>
<h2>LIST OF STONES</h2>
<table id="applicationTable" class="table table-striped table-bordered">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Stone)
</th>
<th>
#Html.DisplayNameFor(model => model.Applicant)
</th>
<th>
#Html.DisplayNameFor(model => model.Org)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Stone)
</td>
<td>
#Html.DisplayFor(modelItem => item.Applicant)
</td>
<td>
{#Html.DisplayFor(modelItem => item.Org)
</td>
<td>
#Html.ActionLink("Details", "Details", new { Id = item.Id })
</td>
</tr>
}
</tbody>
#section Scripts{
<script type="text/javascript">
$(document).ready(function () {
$('#applicationTable').DataTable();
});
</script>}
Here is the controller
public async Task<ActionResult> Index()
{
return View(await db.StoAppnOrgViewObj.ToListAsync());
}
Here is the Search box.
You should not be loading all 12k data on the UI. Instead use server side paging which will give the user similar experience but performance wise will be faster. The system will not be slower. The data will grow over the time and you will have to shift to server side logic anyways in the future.
You can also use the progress indicator that comes with datatable. All you have to do the followings:
$('#example').DataTable( {
"processing": true,
"serverSide": true,
"ajax": "../server_side/scripts/test.php"
} );
For the server side logic, you can follow the codes from here.

How to use EditorFor to save changes to the Model?

I have a view like this:
#model IEnumerable<Namespace.MyClass>
#using Newtonsoft.Json;
<form asp-action="Update">
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Product)
</th>
<th>
#Html.DisplayNameFor(model => model.IsAvailable)
</th>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Product)
</td>
<td>
#Html.EditorFor(modelItem => item.IsAvailable)
</td>
</tr>
}
</tbody>
</table>
<div>
<a href=#Url.Action("SaveChanges", "Product", new {productList = JsonConvert.SerializeObject(Model) })> Save changes</a>
</div>
</form>
where SaveChanges looks like this:
[HttpGet] // Perhaps it should be HttpPost here, but if I change it to that nothing happens when I run the program after clicking the "Save changes" link
public ActionResult SaveChanges(string productList)
{
List<MyClass> products = JsonConvert.DeserializeObject<List<MyClass>>(productList);
// Here I continue with SqlCommand to later make an UPDATE to a database changing the value of IsAvailable which is the only adjustable value in my view
}
My issue is that when I run the program and I change IsAvailable (which is a bool) from false to true in my view and press "Save Changes", the model does not change, i.e. productList still has the value False for IsAvailable for that particular product.
Does anybody have an idea as to why? From my understanding if I have a and
Model information is not updated when you send the model to the action with the link. And the same initial amount is sent.
The changes you make to the model fields are only in the html controls and have nothing to do with the model. The model is updated when you post the form information.
I submitted the form to jQuery in the following code
in view
#model List<Namespace.MyClass>
#using (Html.BeginForm("SaveChanges", "Product", FormMethod.Post))
{
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.FirstOrDefault().Product)
</th>
<th>
#Html.DisplayNameFor(model => model.FirstOrDefault().IsAvailable)
</th>
</thead>
<tbody>
#for (int i = 0; i < Model.Count(); i++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => Model[i].Product)
</td>
<td>
#Html.EditorFor(modelItem => Model[i].IsAvailable)
</td>
</tr>
}
</tbody>
</table>
<div>
#Html.ActionLink("Save changes", "", null, new { #id = "submit"})
</div>
}
#section scripts{
<script type="text/javascript">
$("#submit").click(function () {
document.forms[0].submit();
return false;
});
</script>
}
action in controller
[HttpPost] // Perhaps it should be HttpPost here, but if I change it to that nothing happens when I run the program after clicking the "Save changes" link
public ActionResult SaveChanges(IEnumerable<MyClass> products)
{
// Here I continue with SqlCommand to later make an UPDATE to a database changing the value of IsAvailable which is the only adjustable value in my view
}

Trouble getting textbox value from view to controller in ASP.NET MVC

I'm still a beginner in ASP.NET MVC. I have a project that I am working on right now with two views and 1 controller. 1 scan page, 1 data entry page and 1 controller called LprController.
So on the data entry cshtml I have the button that I'm trying to get the data from called lotnoTBX.
div class="col-md-4 col-sm-offset-3">
<img src="~/Images/Capture.PNG" class="media-object center-block"/>
<div class="block-main col-sm-8 col-sm-offset-4">
<h2>Scan Lot</h2>
<input id="lotnoTBX"/>
<div class="container-fluid row">
<button id="enterBtn" type="submit" class="btn btn-primary btn-group-lg" style="margin-top:5px;" onclick="location.href='#Url.Action("DataEntry", "Lpr")'">Enter</button>
</div>
</div>
</div>
Then on the controller page things are a bit confusing. I'm not sure where to save or how to save the lotnoTBX data. Basically I'm using a webservice to get a query from the result of the textbox and post it to the dataentry page using Models.
public ActionResult ScanPage(FormCollection form)
{
string lotno = form["lotnoTBX"];
Session["lotno"] = lotno;
return View();
}
public ActionResult DataEntry()
{
FCoai.FCWCFT.PCSInterfaceClient client = new FCWCFT.PCSInterfaceClient("BasicHttpBinding_IPCSInterface1");
FCoai.FCWCFT.PCSResult x = client.getCurrentLotDetail(Session["lotno"].ToString());
return View();
}
Then here's the data entry page where I'm trying to post the model's in the cshtml.
<table>
<thead>
<tr>
<th class="table-active">OP</th>
<th class="table-active">Lotno</th>
<th class="table-active">Itemcode</th>
<th class="table-active">Marking</th>
<th class="table-active">Output</th>
</tr>
<tr>
<td #Model.op></td>
<td #Model.lotno></td>
<td #Model.itemCode></td>
<td #Model.marking></td>
<td #Model.output></td>
</tr>
</thead>
</table>
*edit I missed out one actionresult which might have been confusing for some people
Please help.
So I managed to get the textbox values to return. It turns out I had to use a form and a model as a parameter in the controller in order to do so.
Here's the scan lot cshtml
<h2>Scan Lot</h2>
#using (Html.BeginForm("ScanPage"))
{
#Html.TextBoxFor(Model => Model.lotno)
<input type="submit" value="Enter"/>
}
And here are the controllers
public ActionResult ScanPage()
{
return View();
}
[HttpPost]
public ActionResult ScanPage(FCoai.FCWCFT.PCSResult pCS)
{
string lotno = pCS.lotno;
Session["lotno"] = lotno;
return RedirectToAction("DataEntry", "Lpr");
}
public ActionResult DataEntry()
{
FCoai.FCWCFT.PCSInterfaceClient client = new FCWCFT.PCSInterfaceClient("BasicHttpBinding_IPCSInterface1");
FCoai.FCWCFT.PCSResult x = client.getCurrentLotDetail(TempData["lotno"].ToString());
//Passing data from controller to view
ViewData["Lot"] = x;
return View();
}
<div class="row">
<div class="col-md-12">
<table>
<thead>
<tr>
<th class="table-active">OP</th>
<th class="table-active">Lotno</th>
<th class="table-active">Itemcode</th>
<th class="table-active">Marking</th>
<th class="table-active">Routing</th>
</tr>
<tr>
#{
//This is how display data from view to controller
var lot = (FCoai.FCWCFT.PCSResult)ViewData["Lot"];
}
<td>#lot.op</td>
<td>#lot.lotno</td>
<td>#lot.itemCode</td>
<td>#lot.markLow</td>
<td>#lot.rout</td>
</tr>
</thead>
</table>
</div>
</div>
Edit here's my final answer.
Even though I have managed to find the answer to my own question I would appreciate if you guys could give tips on conventions or otherwise that I could have missed out on.

Displaying a single record in the asp.net for the _layout.cshtml view

I'm out of ideas, but I guess it's because I'm a noob in asp.net.
I have a MVC3 project and my idea was to have 2 sections:
Section Main is for displaying tables and news and all the staff that changes when entering different pages.
Section Main_profile is for displaying profile info (name, email etc) for currently logged user. Here is the problem. I know I need to put the code for Main_profile displaying in the _Layout.cshtml, as I want that information to be shown all the time. I have tried this:
<section id="main_profile">
#Html.Action("Profile", "Person", new { name = User.Identity.Name })
</section>
Profile is a method in my PersonController, which looks like this:
public ViewResult Profile(string name)
{
string person_n = name;
return View(db.Persons.Where(s => s.Username.Equals(person_n)));
}
At the end, there is a view for Profile:
#model IEnumerable<Bachelor.Models.Person>
<h2>Your profile</h2>
<table border = "1">
<tr>
<th>
Username
</th>
<th>
Birthday
</th>
<th>
Education
</th>
<th>
Email
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Username)
</td>
<td>
#Html.DisplayFor(modelItem => item.Birthday)
</td>
<td>
#Html.DisplayFor(modelItem => item.Education)
</td>
<td>
#Html.DisplayFor(modelItem => item.Email)
</td>
</tr>
But what I get is this "An unhandled exception of type 'System.StackOverflowException' occurred in Unknown Module."
Don't know if that may have something to do with it, but in the Main section, on some pages there is a table of records being displayed.
What am I doing wrong here?
Set your Layout to null in your partial. What is doing is recursively calling itself:
#{ Layout = null; }

Categories