How to display IEnumerable in view? [duplicate] - c#

This question already has answers here:
Display List in a View MVC
(2 answers)
List model razor view
(2 answers)
Closed 3 years ago.
Im doing comment section for product and have some troubles with displaying comments view. I made model from 2 models to display them in one view, but my way to display IEnumerable as list gets me an error. How can i modify my code to get this working?
Model
public class DetailsViewModel
{
public Product Product { get; set; }
public IEnumerable<Comments> Comments { get; set; }
}
Controller
public ActionResult ProductDetails(int? id)
{
DetailsViewModel detailsViewModel = new DetailsViewModel();
detailsViewModel.Product = db.Product.Find(id);//this is working
detailsViewModel.Comments = db.Comments.Where(c => c.Id_Product == id).OrderBy(x => x.DateComment).ToList();
return View(detailsViewModel);
}
View
#model Database.Models.DetailsViewModel
<ul>
#Html.DisplayFor(x => x.Comments.DateComment) //getting error here 'IEnumerable<Comments>'
#Html.DisplayFor(x => x.Comments.Comment) // does not containt definiton for 'Comment'
<ul>
i want to get something like this:
2019-06-25: Foo
2019-06-25: FooFoo

You can use a foreach loop to achieve your functionality. A foreach loop will iterate over your IEnumerable and display each element in the list. Specifically to your case, you can do:
<ul>
#foreach(var comment in Model.Comments)
{
<li>#comment.DateComment</li>
<li>#comment.Comment</li>
}
</ul>

Create a DisplayTemplate for your Comment model and then simply use
#Html.DisplayFor(x => x.Comments)
which will loop through them and use the DisplayTemplate to render each.

Related

Add model into model using Html helper HiddenFor C# MVC

I have a model like
public class Model
{
public int Value { get; set; }
public List<OtherModel> List { get; set; }
}
public class OtherModel
{
public int Value1 { get; set; }
public int Value2 { get; set; }
public bool IsPropTrue { get; set; }
}
I am using Model in a View where I'm looping through the List to show data in a table.
Depending on whether one of the properties (IsPropTrue) in OtherModel is true or false, I want to use the HiddenFor Html helper and send the data to the HttpPost controller.
#model Model
#foreach (var item in Model.List)
{
if (item.IsPropTrue)
{
#Html.HiddenFor(model=> item.Value1)
#Html.HiddenFor(model=> item.Value2)
}
}
I think it doesn't work because I should in some way add these properties to the OtherModel, which is inside the Model; But the way I have it now, I am adding properties to Model.
you can do it like this :
#model Model
#foreach (var item in Model.List)
{
if (item.IsPropTrue)
{
#Html.HiddenFor(model => model.List[Model.List.IndexOf(item)].Value1)
#Html.HiddenFor(model => model.List[Model.List.IndexOf(item)].Value2)
}
}
this way the binding system will bind the hidden fields with your List OtherModel in the Model
if you want send an array to server based on the Model you have to use indexer in #Html.HiddenFor .
#model WebApplication1.Models.MyModel
<form>
#if (Model != null && Model.List != null)
{
for (int i = 0; i < Model.List.Count; i++)
{
if (Model.List[i].IsPropTrue)
{
#Html.HiddenFor(model => Model.List[i].Value1)
#Html.HiddenFor(model => Model.List[i].Value2)
}
}
}
<button type="submit">submit</button>
</form>
if you want know reason of using indexer on model i recommend How does MVC 4 List Model Binding work?
Consider if it the responsibility of the view or the controller action to make the decisions - you can send everything back to the action to do the decision making.
In your Views/Shared folder, create a controller called EditorTemplates
In this folder, add a partial view called OtherModel
In this view, set the model to OtherModel and set the Layout=null
Add the three OtherModel fields in EditorFor (and HiddenFor if not displaying isPropTrue). This partial view displays just one instance of your list.
In your main view, use the above editor model like so. MVC will take care of all rendering and postback of the Model State for your complete list of items. We like one-liners...
#Html.EditorFor(model => model.OtherModel)
When the data is subsequently posted back to an action, Model State has wrapped up all of your displayed items into a list again, so you can check the isPropTrue value for each item on the server.
The only issue with MVC is that is you pass an empty list out to a view, you get a null value back, so just replace this with an empty list when null is returned

Data Binding in ASP.NET MVC

I know it would be a basic question but I'm a newbie to ASP.Net MVC. I have fetched data from database using LINQ but there is an issue. I wanna bind that data with input fields of a customized webform. (I'm using MVC). I wanna populate the input fields of webform with fetched data. I'm using EF Database first approach.
My Controller and view is attached.
Controller ActionMethod
public class HomeController : Controller
{
public ActionResult Index()
{
AutoRTGSEntities_1 dc = new AutoRTGSEntities_1();
//dc.policies.Where(cb => cb.Section_Key.Contains("SenderBIC"));
return View(dc.policies.Where(cb => cb.Policy_Section.Contains("RTGS")).ToList()); //get RTGS policy section data
}
}
View
#model IEnumerable<Swift_MT_103.policy>
#{
ViewBag.Title = "Home Page";
}
<div> #Model{ #Html.TextBoxFor(x => x.data_Value)) } </div>
<div> <input type="text" name="ReceiverBIC" id="ReceiverBIC" /> </div>
Rest is HTML and CSS. Snap is attached.
Here's a very basic example of how to this. Let's say you have following class:
public class User
{
public int Id { get; set; }
[Display(Name = "Name")]
public string Name { get; set; }
[Display(Name = "E-mailaddress")]
public string E-mail { get; set; }
}
In the controller you get the user:
public ActionResult Index(int id)
{
var user = Db.Users.FirstOrDefault(x => x.Id == id);
if(user != null)
{
return View(user);
}
//Return to the 'Error' view as no user was found
return View("Error");
}
You also need a View to show everything on screen. Make it a strongly typed view, this way you can pass a Model to it. This class will hold all data you want to pass to the view. Code of the view:
//This line lets the view know which class represents the model
#model User
#Html.LabelFor(m => m.Name)
#Html.TextBoxFor(m => m.Name)
#Html.LabelFor(m => m.Name)
#Html.TextBoxFor(m => m.Name)
Using the Razor syntax instead of plain HTML it is very easy to construct and bind your form elements to the corresponding data. In this case the label will show the value of the Display attribute in the User class and the values of the user will be filled in the textboxes.
More reading:
Getting started with ASP.NET MVC 5
ASP.NET MVC Overview
Update:
In case you have a list of objects, you need to enumerate them in the view:
#model IEnumerable<string>
#foreach (var value in Model)
{
<div>#value</div>
}
And if the model is a class and has a property that is a list:
//Let's say a user has lots of names
public class User
{
public int Id { get; set; }
public List<string> Names { get; set; }
}
//View:
#model User
#Html.TextBoxFor(m => m.Id)
#foreach (var name in Model.Names)
{
<div>#name</div>
}
Try to implement a correct ASP.NET MVC architecture. To get this completed, you'll need to use proper Razor (.cshtml type) Syntax in your Views. Best practice:
Create a dedicated ViewModel class in the Model directory. You might call it CustomerCreditTransferViewModel for example. It should contain all Properties you want to display/edit anywhere on the page.
Once you selected your data from your DBContext in your Action, create an instance of CustomerCreditTransferViewModel and populate all fields from the result.
Update your View to use #model CustomerCreditTransferViewModel instead of Swift_MT_103.policy (believe me, this is going to make your live much easier in future)
Copy-paste your raw HTML Code into the page and start looking for all Fields you want to bind, e.g. Text fields (<input type="text" name="accountno" value="" />) and replace them with the Razor Syntax for Data Binding (#Html.TextBoxFor(x => x.AccountNo)). If done correctly, they should be populated now.
Next step is probably the POST. Follow the base MVC Post technique from the Tutorials. Ensure that the Posted Value is of type CustomerCreditTransferViewModel) again, so you can easily validate values and map back to type of Swift_MT_103.policy.

How to post List<Model> using partial view in asp.net mvc? [duplicate]

This question already has answers here:
MVC Form not able to post List of objects
(3 answers)
Closed 5 years ago.
Main question: Is it possible to post a list of model using partial view in asp.net mvc?
Example: Lets assume a class as Student having 2 properties(RollNo(int) and Name(string))
public class Student
{
public int RollNo { get; set; }
public string Name { get; set; }
}
Controller having post method where I want list of students from partial view
[HttpPost]
public ActionResult PostListOfStudents(List<Student> lstStudents)
{
//some logic
}
Yes sure you can.
Here is partial view model:
#model List<Student>
You only have to iterate over your list model like below:
#Html.BeginForm("action", "controller", FormMethod.Post)
{
if (Model != null)
{
for (var i = 0; i < Model.Count; i++)
{
#Html.TextBoxFor(m => Model[i].Name)
#Html.TextBoxFor(m => Model[i].RollNo)
}
<input type="submit" value="Post Data" />
}
}
You can pass the list of Students in partial view as below:
#Html.Partial("_partialview", listOfStudents);
Then at your post action you will get the list of student. Just be sure to use proper input extension methods in your case.

How to persist ICollection entity property between requests in Razor

I am working on ASP.NET MVC 4 application. I use EF 5 and Code First. I have two entities with 1:N relation:
public class Menu
{
//some properties
public virtual ICollection<Document> Documents { get; set; }
}
and:
public class Document
{
//some properties..
public int MenuID { get; set; }
public virtual Menu Menu { get; set; }
}
I have Edit view with [HttpPost] and [HttpGet] methods. When I pass the model through the GET action like this :
Menu model = unitOfWork.MenuRepository.GetById(Id);
if (model != null)
{
return View(model);
}
everything is right, I can see that model contains 1 Documents but then in my razor view if I simply try:
#Html.HiddenFor(m => m.Documents)
then when I submit the form to the Post action I can see that the Documents property is null.
How can keep Documents persistent?
Anything with a collection will not get rendered as you are expecting. you need to create say, a displaytemplate which expects a collection and then render our the properties of the documents in a HiddenFor or if you dont want a display template then do the same but on the view in question.
for example, this is what you need to do:
#for(int counter = 0; counter < Model.Documents; counter++)
{
#Html.HiddenFor(m => Model.Documents[counter].Id)
#Html.HiddenFor(m => Model.Documents[counter].Title)
// and so on
}
so now when you postback, it has all the properties it needs for the engine to bind to and pass it to your controller method and serve it up.
Have you looked through the html, that is generated ? Take a look )
This answer and this one provide workarounds.

MVC3 how to post a list within a class in controller?

I have a class:
public class CarList
{
public int quantity{get;set;}
public List<Car> Cars {get;set;}
}
public class Car {
public string Name {get;set;}
}
I then create a car list with three cars in the list. I then display info on the screen using for loop Model.Cars within a . When I submit the form, quantity field has a valid value but Cars is null.
[HttpPost]
public ActionResult Save(CarList list)
{
//why is list.Cars NULL when i am posting three items in the list
}
View:
Model = Car, added a row
Added new editor template for Car with <tr><td>Name</td><td>Html.TextBoxFor(x=>Model.Name)</td></tr>
And in main view:
Model = CarList, added the forloop
#{foreach (Car item in Model.Cars)
{
#Html.EditorFor(x=>item);
}
Actually you don't need to loop through the cars collection. You just have it like
#Html.EditorFor(x => x.Cars)
Use an EditorTemplate and you will be good.
Create a Folder Called "EditorTemplates" and create a view (the editor template) with the name Car.cshtml
Now Add the below code to this new view.
#model Car
<p>
#Html.TextBoxFor(x => x.Name)
</p>
Now in your Main View, Use the Html.EditorFor HTML helper method to call this editor template
#model SO_MVC.Models.CarList
<h2>CarList</h2>
#using (Html.BeginForm())
{
<p>Quanitty </p>
#Html.TextBoxFor(x => x.quantity)
#Html.EditorFor(x=>x.Cars)
<input type="submit" value="Save" />
}
Now have an HTTPPOst action method to accept the form posting
[HttpPost]
public ActionResult CarList(CarList model)
{
//Check model.Cars property now.
}
You will see the results now
I think this is the issue:
#foreach (Car item in Model.Cars)
{
#Html.EditorFor(x=>item);
}
Change it to
#foreach (Car item in Model.Cars)
{
#Html.EditorFor(x=>item.Name);
}
It might a case of the model binder not being smart enough to bind more than one level down, although I don't remember ever having that issue. it may also help to add Glimpse (http://getglimpse.com/) to your project so that you can see how the request is actually processed.

Categories

Resources