I'm using paging with ASP.NET MVC, but I'm losing model data when navigating to next page.
Here is the code:
Partial view:
#using PagedList;
#using PagedList.Mvc;
#model Models.MyObject
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
<table class="table table-striped table-hover sortable">
<thead>
<tr>
<th width="240">#Model.HeaderNames[0]</th>
<th width="240">#Model.HeaderNames[1]</th>
<th width="240">#Model.HeaderNames[2]</th>
<th width="240">#Model.HeaderNames[3]</th>
<th width="120" class="no-sort"></th>
</tr>
</thead>
<tbody>
#foreach (var member in Model.PagedModelList)
{
<tr>
<td><span class="sort-field-value">#member.Thead1</span></td>
<td><span class="sort-field-value">#member.Thead2</span></td>
<td><span class="sort-field-value">#member.Thead3</span></td>
<td><span class="sort-field-value">#member.Thead4</span></td>
</tr>
}
</tbody>
</table>
<footer>
<div>
Page #(Model.PagedModelList.PageCount < Model.PagedModelList.PageNumber
? 0 : Model.PagedModelList.PageNumber) of #Model.PagedModelList.PageCount
#Html.PagedListPager(Model.PagedModelList, page =>Url.Action("Reports",new { #page = page, FirstLoad = false }))
</div>
</footer>
Controller :
public ActionResult Reports(MyObject model, int? page, bool FirstLoad = true)
{
model.pageSize = 4;
model.pageNumber = (page ?? 1);
if (FirstLoad)
{
// getting the data from database here
// ... code
// assigning pagemodelist
model.PagedModelList = model.ModelList.ToPagedList(model.pageNumber, model.pageSize);
}
// here sending the model and all is good
return PartialView("_MyView", model);
}
Model
public class MyObject
{
public int SelectedPeriod { get; set; }
public List<SecondObject> ModelList = new List<Secondobject>();
public IPagedList<Secondobject> PagedModelList ;
public int pageSize { get; set; }
public int pageNumber { get; set; }
}
Second model class:
public class SecondObject
{
public string Thead1 { get; set; }
public string Thead2 { get; set; }
public string Thead3 { get; set; }
public string Thead4 { get; set; }
}
Expected to get next page but all I get is empty model which causes null reference when sending again to view from controller. What am I doing wrong here?
I'm getting right data in model the first time, I show the table with correct data, then when clicking on next page I debug in the controller so I got empty model.PagedModelList, even some other empty model properties .
Any help appreciated
Maybe, try to pass your model in parameters like :
#Html.PagedListPager(Model.PagedModelList, page =>Url.Action("Reports",new {#model = Model, #page = page, FirstLoad = false }))
Edit :
Another solution is to remove MyObject from parameters.
Load each time your data from your database. You can follow the example in
GitHub project
Related
This is the model UserPosts.cs:
public int Id { get; set; }
public string Destination { get; set; }
public DateTime DepartureDate { get; set; }
public string Meetplace { get; set; }
public byte NumberofSeats { get; set; }
public virtual ApplicationUser User { get; set; }
public string UserId { get; set; }
This is the Create method in the controller:
public ActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(UserPosts userposts)
{
var userId = User.Identity.GetUserId();
if (ModelState.IsValid)
{
userposts.UserId = userId;
_db.UserPosts.Add(userposts);
_db.SaveChanges();
return RedirectToAction("Index","UserPosts");
}
return View(userposts);
}
This is the Index view:
#model IEnumerable<Carpool.Models.UserPosts>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>All posts</h2>
<div class="allposts">
#foreach (var m in Model)
{
<div class="posts">
<table class="table">
<tr>
<td><b>Destination</b></td>
<td>#m.Destination</td>
</tr>
<tr>
<td><b>Departure Date</b></td>
<td>#m.DepartureDate</td>
</tr>
<tr>
<td><b>Meetplace</b></td>
<td>#m.Meetplace</td>
</tr>
<tr>
<td><b>Number of Seats</b></td>
<td>#m.NumberofSeats</td>
</tr>
<tr>
<td>
------>Here I want to add an actionlink/button<------
}
</td>
</tr>
</table>
</div>
<br /><br />
}
</div>
What I want to do is: when the user who is logged in click the actionlink or button that is displayed for every post I want to save that post in another view only for that user who clicked it and in that view I want to save all posts when the user click on the actionlink or button. When the user click on the actionlink or button I want NumberofSeats property to decrease with 1. Please help me, I am trying to do this for some days and I haven't found a solution yet. Thank you!
In my WebApp I consume a wcf web service and in my example I consume a Method that returns more than 400 value type. In the first the WebApp will show two column in the View(Table)
//Model
public class OrdersviewModel
{
public int Articlenr { get; set; }
public string ArticleName { get; set; }
}
Later the user has the possibility that he can add or show up new column
Value,The Question is how would be the model??
That is your model:
public class MyViewModel
{
public Dictionary<int, string> OrdersViewDictionary { get; set; }
}
into the view you could use dictionary like that
#model MyViewModel
<table class="table-bordered">
<thead>
<tr>
<th>Index key</th>
<th>Value</th>
</tr>
</thead>
<tbody>
#foreach (var pairData in Model.OrdersViewDictionary) {
<tr>
<td>#pairData.Key</th>
<td>#pairData.Value</th>
</tr>
}
</tbody>
</table>
I can't seem to find how to build a proper solution for a one to many checkbox.
So what do i have :
I have an article and an admin user can set user rights to that article.
So in my article right page you have an overview with all the users.
My article:
public partial class Artikel
{
public Artikel()
{
this.ArtikelLinks = new HashSet<ArtikelLink>();
this.ArtikelRights = new HashSet<ArtikelRight>();
}
public int id { get; set; }
public string code { get; set; }
public string naam { get; set; }
public virtual ICollection<ArtikelLink> ArtikelLinks { get; set; }
public virtual ICollection<ArtikelRight> ArtikelRights { get; set; }
}
My rights class
public partial class ArtikelRight
{
public int id { get; set; }
public System.Guid userId { get; set; }
public int artikelId { get; set; }
public bool hasRight { get; set; }
public virtual Artikel Artikel { get; set; }
}
How do i build my view? i tried several ways but i can't seem to save my data.
this is my rights view at the moment:
#using (Html.BeginForm()) {
<table width="90%" align="center" class="table table-striped">
<thead>
<tr>
<th align="left">Gebruiker</th>
<th align="left">Heeft toegang</th>
</tr>
</thead>
#Html.EditorFor(x => Model.ArtikelRights, "ArtikelRight")
</table>
<br />
<div class="pull-right">
<input type="submit" value="Opslaan" class="btn btn-sm beige" />
</div>
}
And this is my partial Artikel right view:
#model IEnumerable<GtiProducts.Models.ArtikelRight>
#foreach (var item in Model) {
<tr>
<td>
#Membership.GetUser(item.userId).UserName
</td>
<td>
#Html.EditorFor(x => item.hasRight)
</td>
</tr>
}
My save action is:
public ActionResult Rights(Artikel art)
{
repo.SaveChanges();
return View(art);
}
When i debug my art.ArtikelRights is null.
How can i fix this and what's the best solution to do this with the entity framework?
Rename the partial to make it an EditorTemplate- /Views/Shared/EditorTemplates/ArtikelRight.cshtml, then make the following modifications
#model GtiProducts.Models.ArtikelRight // not IEnumerable
<tr>
<td>
#Html.CheckBoxFor(m => m.hasRight)</td>
#Html.LabelFor(m => m.hasRight, "....") // the users name?
#Html.HiddenFor(m > m.id) // or what ever property you need to identify the ArtikelRight.cshtml
</td>
</tr>
Then in the main view
<tbody>
#Html.EditorFor(x => Model.ArtikelRights)
</tbody>
This will correctly name you controls with indexers so they can be bound to your model on post back, for example
<input type="checkbox" name="ArtikelRights[0].hasRight" ...>
<input type="checkbox" name="ArtikelRights[1].hasRight" ...>
Side note: You should not be using #Membership.GetUser(item.userId).UserName in the view. Instead create a view model with only those properties you need in the view (which appears to be id and hasright, and include a property for the users display name (and populate it in the controller).
I have the following Model:
public class ContractPlain
{
public int Id { get; set; }
public Guid ContractGuid { get; set; }
public int SenderId { get; set; }
public int RecvId { get; set; }
public int ContractType { get; set; }
public string ContractStatus { get; set; }
public DateTime CreatedTime { get; set; }
public DateTime CreditEnd { get; set; }
}
public class Contrtacts
{
List<ContractPlain> listOutput;
public void Build(List<ContractPlain> listInput)
{
listOutput = new List<ContractPlain>();
}
public List<ContractPlain> GetContracts()
{
return listOutput;
}
internal void Build(List<contract> currentContracts)
{
throw new NotImplementedException();
}
}
As you can see, I defined a whole collection.
Why?
I need to render the data in table for user, because there are several rows which belongs to the exact/unique user (e.g. 20-30 shop items are referred to the single client).
So, I'm getting data from the DB using ADO.NET Entity. The binding question to the model instance in Controller is done and I don't have issues with that, I do with the rendering question only.
I think, it could be used with the #for stuff, but didn't know, how it would be better using especially my custom model.
So, how can I render the data in View using my model?
Thanks!
See the view below. You simply foreach over your collection and display the Contracts.
Controller:
public class ContactsController : Controller
{
public ActionResult Index()
{
var model = // your model
return View(model);
}
}
View:
<table class="grid">
<tr>
<th>Foo</th>
</tr>
<% foreach (var item in Model) { %>
<tr>
<td class="left"><%: item.Foo %></td>
</tr>
<% } %>
</table>
Razor:
#model IEnumerable<ContractPlain>
<table class="grid">
<tr>
<th>Foo</th>
</tr>
#foreach (var item in Model) {
<tr>
<td class="left"><#item.Foo></td>
</tr>
#}
</table>
If your action returns a List of contracts you can do the following in the view:
#model IEnumerable<ContractPlain>
#foreach(ContractPlain contract in Model)
{
<ul>
<li>#contract.ContractGuid</li>
<li>#contract.SenderId</li>
<li>#contract.ContractStatus</li>
<li>#contract.CreditEnd</li>
</ul>
}
I have a web app where I want to show a form for a Test object. Different Test instances can have different schemas. I can display this pretty nicely, but it won't populate all the data from the form back into my model.
Here are my model classes:
public class EnterTestData
{
public string StudyId { get; set; }
public Test Test { get; set; }
}
public sealed class Test
{
public string Identity { get; set; }
public string Name { get; set; }
public IEnumerable<TestField> Fields { get; set; }
}
public sealed class TestField
{
public string Identity { get; set; }
public string Name { get; set; }
public string Value { get; set; }
public string Type { get; set; }
}
Here is the relevant portion of my View:
<% Html.BeginForm("PostTestData", "StudiesUserInterface"); %>
<table>
<%
foreach (var testField in Model.Test.Fields)
Html.RenderPartial("UserControls/TestFieldUserControlascx", testField);
foreach (var category in Model.Test.Categories)
{
%>
<tr>
<td colspan="2" style="font-style: italic; text-align: center;">
<%=category.Name %>
</td>
</tr>
<%
foreach (var testField in category.Fields)
Html.RenderPartial("UserControls/TestFieldUserControlascx", testField);
}
%>
<tr>
<td colspan="2" style="text-align: right;">
<input type="submit" name="newsletter" value="Enter Result" />
</td>
</tr>
</table>
<% Html.EndForm(); %>
And the partial view for the actual text boxes:
<tr>
<td>
<%= Model.Name %>
</td>
<td>
<%
switch (Model.Type)
{
case "date":
case "text":
case "number":
%>
<%= Html.TextBox(Model.name, Model.Value) %>
<% break;
default: %><%= Html.Label("Unknown data type") %><% break;
}
%>
</td>
</tr>
Update Controller methods:
public ActionResult EnterTestData(string studyId, string testId)
{
var testDefinition = ServiceKitLocator.GetStudyService().GetTestDefinition(testId);
return View(new EnterTestData { StudyId = studyId, Test = testDefinition });
}
public ActionResult PostTestData(EnterTestData model)
{
//I'm just putting a break point here and checking the model in the debugger for now
return RedirectToAction("Index");
}
The problem is that Test is null when it comes back to my Controller. How do I get it to be populated? Why is it null?
I think the problem is the Html.TextBox element.
If it's correct that the model in your view is type of "Test" but in your controller action you want to bind to type of "EnterTestData" which has a property of type "Test" named "Test"
Then your TextBox should be initializied like
Html.TextBox("Test.Name", Model.Value)
The important part is the name parameter. The modelbinder matches this name with the properties of the model type in your post action, in your case "EnterTestData".
You can also use an editor template view. Which does the same as your partial view.
In your project go to Views\Shared\ and create a folder named EditorTemplates, if not exists.
In this folder create a partial view and name it like the class/type the template should be for. In your case "TestField.ascx". Actually you can copy and rename your existing partial view.
In you main view you have to change 2 things:
- use for instead of foreach
- call the editor template in the loops
like:
for(int i = 0; i < Model.Test.Fields.Count(); i++)
Html.EditorFor(Model => Model.Test.Fields[i]);
In the template view you have to change one thing:
- user TextBoxFor instead of TextBox
like:
Html.TextBoxFor(Model => Model.Value)
I use this pattern often. It makes it easy to bind complex models.
You may have a look at the generated HTML