This is my controller:
[HttpPost]
public ActionResult RegisterUser(User user)
{
var users = new User(user);
Context.Users.Insert(user);
return RedirectToAction("RegisterdUsers");
}
public ActionResult RegisterdUsers()
{
var users = Context.Users.FindAll();
return View(users);
}
And here is my view:
#model IEnumerable<SportsFantasy_2._0.Models.User>
#{
ViewBag.Title = "RegisterdUsers";
}
<h2>RegisterdUsers</h2>
<table>
<tr>
<th>
#Html.DisplayNameFor(m => m.username)
</th>
</tr>
So as you can see i send users to my view and i want to use IEnumerable to iterate through users. But when i try to use the model m=> m.username it cant find username?
What am i doing wrong?
m represents your Model. And your model is IEnumerable<SportsFantasy_2._0.Models.User> which doesn't have a username property.Use a loop if you want to display all users.
you have to iterate as it is IEnumerable of some type not a simple type:
#foreach(var item in Model)
{
<th>
#Html.DisplayNameFor(m => item.username)
</th>
}
Related
I have a index in controller and view following.
When I enter student ID on textbox search, I want to display information of student and list all activities of them. How to do that.
Thank you so much!
Controller:
public ActionResult Index(string Sid)
{
var grad = db.Gradings.Include(g => g.Activity).Include(g => g.Student).Where(g => g.StudentID == Sid).ToList();
}
View:
<div class="col-xs-4">
<p>
#using (Html.BeginForm())
{
<p>
Student ID: #Html.TextBox("Sid",ViewBag.FilterValue as string)
<input type="submit" value="Search" />
</p>
}
<table class="table">
<tr>
<th>Activity Name</th>
....
</tr>
#foreach (var item in Model)
{
<tr>
<td>#Html.DisplayFor(modelItem => item.Activity.Name)</td>
<td>#Html.DisplayFor(modelItem => item.Responsibility)</td>
....
</tr>
}
</table>
</div>
<h3> Total score: #ViewBag.Total</h3>
Thanks for your help!
You need one action to serve your view initially when the user requests it:
public ActionResult Index()
{
return View();
}
Then you need another action to process the user's request when the request submits the form:
public ActionResult Index(string Sid)
{
var grad = db.Gradings.Include(g => g.Activity).Include(g => g.Student).Where(g => g.StudentID == Sid).ToList();
return View(grad);
}
Now grad is a List<Grading> and above we are passing it to the view as the model so make sure you use it in your view. You may need to include the namespace for List and Grading:
#model List<Grading>
Finally instead of using foreach in your view, use a for loop so your HTML tags have unique IDs. Right now (with foreach), all Grading records will have the same name and id attributes.
I am getting the following error.
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[MYAPP.Models.User]', but this
dictionary requires a model item of type
'System.Collections.Generic.IEnumerable`1[MYAPP.Models.ViewModel.AccountViewModel]'.
My code is as follows:
VIEWMODEL
public class AccountViewModel
{
...
public IQueryable<User> user { get; set; }
}
CONTROLLER
public class UserController : Controller
{
private REc db = new REc();
// GET: /User/
public ActionResult Index()
{
AccountViewModel avm = new AccountViewModel();
var users = db.Users.Include(u => u.USERROLE);
avm.user = users;
return View((avm.user).ToList());
}
VIEW
#model IEnumerable<SNAPAPP.Models.ViewModel.AccountViewModel>
#{
ViewBag.Title = "Index";
}
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.USERROLE)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.USERROLE)
</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>
Your razor view is strongly typed to a collection of AccountViewModel class objects. But your current action method code is sending a list of User entity (the entity class which is totally different than your view model class). That is the reason you are getting this type mismatch error.
You should send the correct type from your action method. You may use projection on your linq statement to get a collection of AccountViewModel from the db.Users collection.
var accountViewModelList = db.Users
.Select(x=> new AccountViewModel { Id=x.Id })
.ToList();
return View(accountViewModelList);
The above code will basically create a list of AccountViewModel objects and read each User entity object's Id property value and assign it to the corresponding view model object's Id property. If you want more properties in your view, you should map those as well.
For example, if you have a FirstName property in both your entity class and view model, you may do this,
var accountViewModelList = db.Users
.Select(x=> new AccountViewModel {
Id=x.Id,
FirstName = x.FirstName })
.ToList();
in your controller, use this to return the model to the view
return View(avm.user.AsEnumerable);
your db query returns a IQueryable,
you did put the ToList on the whole model, not on the user field
I have to create one view of invoice. I have many models (tables) and I want to display all data from multiple models in one view of invoice. I created one empty (without model) view and put into a partial views. One of Partial View return one view with one model but this solution return me exception... This is my work:
This is my action in controller:
public ActionResult Customer()
{
var data = db.Customer;
return PartialView("Index", data);
}
public ActionResult Invoice()
{
var data = db.Invoice;
return PartialView("Index", data);
}
public ActionResult Dealer()
{
var data = db.Dealer;
return PartialView("Index", data);
}
public ActionResult Paid()
{
var data = dane.Paid;
return PartialView("Index", data);
}
public ActionResult Products()
{
var data = dane.Products;
return PartialView("Index", data);
}
This is one of partial view:
#model IEnumerable<Invoice_v1._0.Models.Products>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Price)
</th>
<th>
#Html.DisplayNameFor(model => model.Amount)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Price)
</td>
<td>
#Html.DisplayFor(modelItem => item.Amount)
</td>
</tr>
}
</table>
This is my "Index" view with Partial Views:
#Html.Partial("_Customer")
#Html.Partial("_Invoice")
#Html.Partial("_Dealer")
#Html.Partial("_Paid")
#Html.Partial("_Products")
How can I fix them?
If you insist on having a single view, then you can make rendering of partial views conditional:
if (Model != null && Model is Customer)
Html.Partial("_Customer", Model as Customer)
, and so on.
On a related note, since all the models are exclusive (you never have more than one object), I don't see the point of having one Index view. You already have one (partial) view per class, so why not just use them as regular views?
Update
If you choose to return separate view from each of the action methods, then you can do that by specifying the name of each view. Refer to this question for details: How to return ActionResult with specific View (not the controller name)
In your particular case, that would mean:
public ActionResult Customer()
{
return View("_Customer", db.Customer);
}
public ActionResult Invoice()
{
return View("_Invoice", db.Invoice);
}
public ActionResult Dealer()
{
return View("_Dealer", db.Dealer);
}
public ActionResult Paid()
{
return View("_Paid", db.Paid);
}
public ActionResult Products()
{
return View("_Products", db.Products);
}
Make sure that each of the views expects a strongly typed model. That will make it easy to implement the views.
While your approach may work, you will have less or no control over the data (if you want to let's assume join or use any of the parent data). In such situations what I do is create a ViewModel with more than one objects as part of it. For example
public class InvoiceViewModel
{
public InvoiceHead Header { get;set; }
public IList<InvoiceDetail> Details { get; set; }
}
So now I can populate this View Model before going into my view.
public ActionResult Invoice(int id)
{
InvoiceViewModel viewModel = new InvoiceViewModel();
viewModel.Header = db.InvoiceHead.SingleOrDefault(i => i.ID == id);
if(viewModel.Header != null)
{
viewModel.Details = db.Details.Where(d => d.Inv_id == id).ToList();
}
return View(viewModel);
}
Now I can design my view with either Partial views or one whole view for my invoice data.
I will put as model the IEnumerable or IList
if I use partial for both it will be
#model db.Objects.InvoiceHead // for the header
#model IEnumerable // for the details
in html code will be like that
#Html.Partial("~/Views/Customers/_AttachFileList.cshtml")
use your own folder path. hope works
I have a view with a table that displays my model items. I've extracted the relevant portions of my view:
#model System.Collections.Generic.IEnumerable<Provision>
#using (Html.BeginForm("SaveAndSend", "Provision", FormMethod.Post))
{
if (Model != null && Model.Any())
{
<table class="table table-striped table-hover table-bordered table-condensed">
<tr>
...
// other column headers
...
<th>
#Html.DisplayNameFor(model => model.IncludeProvision)
</th>
...
// other column headers
...
</tr>
#foreach (var item in Model)
{
<tr>
...
// other columns
...
<td>
#Html.CheckBoxFor(modelItem => item.IncludeProvision)
</td>
...
// other columns
...
</tr>
}
</table>
<button id="save" class="btn btn-success" type="submit">Save + Send</button>
}
...
}
This works fine and the checkbox values are displayed correctly in the view depending on the boolean value of the IncludeProvision field for the given model item.
As per Andrew Orlov's answer, I've modified the view and controller and the SaveAndSend() controller method is now:
[HttpPost]
public ActionResult SaveAndSend(List<Provision> provisions)
{
if (ModelState.IsValid)
{
// perform all the save and send functions
_provisionHelper.SaveAndSend(provisions);
}
return RedirectToAction("Index");
}
However, at this point the passed in model object is null.
Including the Provision model object for completeness:
namespace
{
public partial class Provision
{
...
// other fields
...
public bool IncludeProvision { get; set; }
}
}
My question is, what is the best way to grab the checked/unchecked value from each checkbox and update the session IncludeProvision field for each model item when the 'SaveAndSend' button is clicked?
You cannot use a foreach loop to generate form controls for properties in a collection. It creates duplicate name attributes (in your case name="item.IncludeProvision") which have no relationship to your model and duplicate id attributes which is invalid html. Use either a for loop (you models needs to be IList<Provision>
for(int i = 0; i < Model.Count; i++)
{
<tr>
<td>....</td>
<td>#Html.CheckBoxFor(m => m[i].IncludeProvision)<td>
</tr>
}
or create an EditorTemplate for typeof Provision. In /Views/Shared/EditorTemplates/Provision.cshtml (note the name of the template must match the name of the type)
#model Provision
<tr>
<td>....</td>
<td>#Html.CheckBoxFor(m => m.IncludeProvision)<td>
</tr>
and in the main view (the model can be IEnumerable<Provision>)
<table>
#Html.EditorFor(m => m)
</table>
As #mattytommo said in comments, you should post your model to controller. It can be done with putting your checkbox inside a form. After clicking on button "Save and exit" all data from inputs inside this form will be serialized and sent to your controller where you can perform manipulations with session variables and so on. After that you can redirect wherever you like.
Model
public class YourModel
{
...
public bool IncludeProvision { get; set; }
...
}
View
#model YourModel
...
#using (Html.BeginForm("SaveAndSend", "Test", FormMethod.Post))
{
...
#Html.CheckBoxFor(model => model.IncludeProvision)
...
<button type="submit">Save and send</button>
}
...
Controller
public class TestController : Controller
{
...
[HttpPost]
public ActionResult SaveAndSend(YourModel model)
{
if (ModelState.IsValid)
{
// Some magic with your data
return RedirectToAction(...);
}
return View(model); // As an example
}
...
}
I have asked this question, I didn't get my answer. So I did much more researches about this and still couldn't find a proper good answer for this.
My controller (shortened):
public ActionResult SearchResult(String sortOrder, String carMake, String carModel)
{
var cars = from d in db.Cars
select d;
if (!String.IsNullOrEmpty(carMake))
{
if (!carMake.Equals("All Makes"))
{
cars = cars.Where(x => x.Make == carMake);
}
}
if (!String.IsNullOrEmpty(carModel))
{
if (!carModel.Equals("All Models"))
{
cars = cars.Where(x => x.Model == carModel);
}
}
switch (sortOrder)
{
case "Model":
cars = cars.OrderBy(s => s.Model);
break;
default:
cars = cars.OrderBy(s => s.Make);
break;
}
return View(cars);
}
My Index view (shortened - this is where user filters cars by different inputs):
#model IEnumerable<Cars.Models.Car>
#using (Html.BeginForm("SearchResult", "Home", FormMethod.Post))
{
<label>Make</label>
<select id="MakeID" name="carMake">
<option>All Makes</option>
</select>
<label>Model</label>
<select id="ModelID" name="carModel">
<option>All Models</option>
</select>
<button type="submit" name="submit" value="search" id="SubmitID">Search</button>
}
My SearchResult view where shows the search results (shortened):
#model IEnumerable<Cars.Models.Car>
<table>
#foreach (var item in Model)
{
<tr>
<td>
<label>Make:</label>
<p>#Html.DisplayFor(modelItem => item.Make)</p>
</td>
<td>
<label>Model:</label>
<p>#Html.DisplayFor(modelItem => item.Model)</p>
</td>
</tr>
}
</table>
Model
My goal: When user clicks on the sort by Model the page will sort the results by Model.
Problem: When the sortby is clicked, all the parameters of action SearchResult will be null since the search value do not exist in SearchResult View.
Question: How to fix this?
Thanks, Amin
UPDATE: Any example would be deeply appreciated. I'm stuck with back-end the whole process of sending and fetching data between controller and view.
You can create one class like below
public CarFilter CarFilter;
public byte PageSize;
public short PageNumber;
public int TotalRows;
where CarFilter is another class where you can store your filters enter by users.
and use this class as a model for your view.so that when you view is loading you can load car filter data.
You can retain your search filters by doing any of the following:
Use sessions to store the filters on your search result view. This way, when you post on the same view using Sort you would still have the search filters.
(I prefer this one) Wrap your model in a class that has properties for your search filters. This way, you will still be able to retrieve the search filters. Provided that you have a POST for SearchResult that accepts the Wrapper Model as parameter.
Create Classes as follow:
class ManageCarSearch
{
public CarFilter CarFilter;
public byte PageSize;
public short PageNumber;
public int TotalRows;
public String sortOrder;
}
Class CarFilter
{
public String carMake,
public String carModel
}
your searchResult view look like below:
#model IEnumerable<car>
<table>
#foreach (var item in Model)
{
<tr>
<td>
<label>Make:</label>
<p>#Html.DisplayFor(modelItem => item.Make)</p>
</td>
<td>
<label>Model:</label>
<p>#Html.DisplayFor(modelItem => item.Model)</p>
</td>
</tr>
}
</table>
Model
and controller as below:
public ActionResult SearchResult(String sortOrder, String carMake, String carModel)
{
var cars = from d in db.Cars
select d;
ManageCarSearch objsearch = new ManageCarSearch();
////your Logic
return View(objsearch);
}
and you serach view look like below:
#model IEnumerable<ManageCarSearch>
#using (Html.BeginForm("SearchResult", "Home", FormMethod.Post))
{
<label>Make</label>
<select id="MakeID" name="carMake">
<option>All Makes</option>
</select>
<label>Model</label>
<select id="ModelID" name="carModel">
<option>All Models</option>
</select>
<button type="submit" name="submit" value="search" id="SubmitID">Search</button>
}