I wish to build a partial view that gets a model column and print it.
Something like that:
At the view:
#model IEnumerable<products_comparison.Models.Product>
#{
ViewBag.Title = "Index";
var Brand = (from r in Model
select r.Brand).Distinct();
}
<h2>
Index</h2>
#Html.RenderPartial("_DisplayAttribute",Brand)
And at the partial view:
<table>
<tr>
<th>
Brand
</th>
</tr>
#foreach (var row in Model)
{
<tr>
<td>
#Html.DisplayFor(r => row)
</td>
</tr>
}
</table>
There are a few problems I run into:
The compiler doesnt allow me to send Barnd to the partial view.
If you look at the partial view code you will see the word Brand, which is the column name. I dont wish to hard-coded the word "Brand" in the partial view, instead I like that the column name will be there.
In the partial view I need to put #model products_comparison.Models.Product, but I dont
want to send the hole table. I want to send only one column - But I dont know what to put there..
Thanks!
EDIT:
Just to clear one thing, I want that the view will call the same partial view for each column in the table(for most of the columns in the table anyway) and each time I'll send a different column(distinct value column to be exact).
Start by refactoring and putting the right logic into the right place. This LINQ query has strictly nothing to do in a view. A view is not supposed to do any LINQ queries or whatever to pull data. A view is supposed to work with data that it is passed to it from the controller action under the form of a view model. A controller action builds and passes an adapted view model that you define for the view.
So as always you start by defining a view model that will be adapted to the requirements of your view:
public class MyViewModel
{
public IEnumerable<Brand> Brands { get; set; }
}
then you write a controller action that will populate this view model and pass it to the view:
public ActionResult Foo()
{
IEnumerable<products_comparison.Models.Product> products = ...
var model = new MyViewModel
{
Brands = (from r in Model select r.Brand).Distinct()
};
return View(model);
}
then a view:
#model MyViewModel
<table>
<tr>
<th>
Brand
</th>
</tr>
#Html.DisplayFor(x => x.Brands)
</table>
and finally you could define a corresponding display template which will automatically be rendered for each element of the Brands collection of your view model (~/Views/Shared/DisplayTemplates/Brand.cshtml):
#model Brand
<tr>
<td>
#Html.DisplayForModel()
</td>
</tr>
For 1 try changing #Html.RenderPartial("_DisplayAttribute",Brand) to #Html.Partial("_DisplayAttribute",Brand)
You will also need to specify the model in the partial view like #model products_comparison.Models.Brand or something like it
Also please clarify 2 & 3 as they are not clear what you want
Related
In MVC 5, i am looping through the Model item in my view.
#foreach (var item in Model.invoices)
During each loop i am calling a partial view
#{
Html.RenderPartial("~/Views/Invoice/CommonSegment.cshtml", item);
}
But i am not able to access model ('item') in CommonSegment.cshtml
Snap from Visual Studio
<tr>
<td class="orderTitle">#item.orderId.label</td>
<td class="orderValue">#item.orderId.value</td>
</tr>
I am referring to same model in View and PartialView.
I wouldn't like to go with ViewBag.
Thanks in advance.
May be you can do this during the Loop,
#foreach (var item in Model.invoices)
{
#Html.RenderPartial("~/Views/Invoice/CommonSegment.cshtml", item);
}
But why writing foreach loops when you can use editor templates.
#model IEnumerable<Invoices>
#Html.EditorForModel()
and then simply define the corresponding editor template (~/Views/Invoice/CommonSegment.cshtml) It will automatically rendered for each element of your model:
#model Invoices
<div>
#Html.EditorFor(x => x.abc)
</div>
I want to create simple list in a form of table like on the image:
I am confused how to implement update/delete actions.
Both are [HttpPost] methods.
But I can't create forms inside <td> tags.
What is the valid way to make a table in the way that I want?
I think I have understood what do you need.
You can make one simple table and into each row put only one td which keep form.
Something like this:
<table>
#{
foreach (var item in Model.MyCollection)
{
<tr>
<td>
<form>
<table>
and hear put your existing row with your columns <tr><td>...</td><td>...</td></tr>
</table>
</form>
</td>
</tr>
}
}
and you will have one form for each record.
I am trying to use a display template (Pet.cshtml), which I have placed in ~/Views/Shared/DisplayTemplates, as per convention.
The Index action gets the IEnumerable and passes it to Index.cshtml, which passes it along to _PetTablePartial. So far, so good. However, when Html.DisplayForModel is called, I get this error:
The model item passed into the dictionary is of type 'Pet', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[Pet]'.
But I (think) I can clearly see that the model item is in fact an IEnumerable. What am I doing wrong?
Controller:
public ActionResult Index()
{
return View(pet.GetPets()); // returns IEnumerable<Pet>
}
Index.cshtml:
#model IEnumerable<Pet>
{Html.RenderPartial("_PetTablePartial", Model);}
...
_PetTablePartial.cshtml:
#model IEnumerable<Pet>
#Html.DisplayForModel()
~/Shared/DisplayTemplates/Pet.cshtml:
#model IEnumerable<Pet>
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
...
Pet.cshtml should have a model type of Pet, because you are only dealing with a single pet here.
DisplayTemplates automatically enumerate over a collection, and call your DisplayTemplate with a single item. That's one of their benefits. You don't need to do any enumeration.
Just change Pet.cshtml's type to Pet
I also suspect you don't want to have a separate table for each pet. So what you want is to create the table and header In your partial view, then only have a single data row in Pet.cshtml, because Pet.cshtml will be called multiple times, once for each row.
PetTablePartial.cshtml:
#model IEnumerable<Pet>
<table>
<tr>
<th> Pet Name </th>
</tr>
#Html.DisplayForModel()
</table>
~/Shared/DisplayTemplates/Pet.cshtml:
#model Pet
<tr>
<td>#Html.DisplayFor(x => x.Name)</td>
</tr>
In the Pet.cshtml you are passing in IEnumerable<Pet>, but then trying to access the Name property of the model. IEnumerable does not have a Name property.
In general, you would wrap this with a foreach loop so you can access the Name property of the elements on the list. However, since you are trying to write out the table header, you only want to write it out once and not traverse the list.
Take a look at these other SO questions:
#Html.DisplayNameFor for details model
How to get the column titles from the Display(Name=) DataAnnotation for a strongly typed list scaffold view at runtime?
is it possible i fill model's fields by content of table's tds. of course without using javascript .
i wanna pass a model to view and get content of tds .
some thing like text box : #Html.TextBoxFor(m => m.username)
is it possible i have some thing like this for tds? what can i put in place of tds?
<tr class="darckTr">
<td>code :</td>
<td id="tdPobox" colspan="3">12345</td>
<td>Email :</td>
<td id="tdEmail">example#yahoo.com</td>
</tr>
It sounds like what you want is a display template. Create a .cshtml view, for example "ContactDetails.cshtml":
#model ContactDetails
<tr class="darckTr">
<td>code :</td>
<td id="tdPobox" colspan="3">#Model.PoBox</td>
<td>Email :</td>
<td id="tdEmail">#Model.Email</td>
</tr>
If the filename of your partial view matches the type in your model, it will be used automatically. Otherwise, you have a couple of options. Either specify the partial on your model, e.g.:
public class MyWrappingClass
{
[UIHint("_ContactDetails")]
public ContactDetails Details { get; set; }
}
And then do this in your view:
#model MyWrappingClass
#Html.DisplayFor(m => m.Details)
Or, just specify the template directly in your view:
#model MyWrappingClass
#Html.DisplayFor(m => m.Details, "_ContactDetails")
Brad Wilson wrote a good blog post on templates, including how they are resolved, here:
http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-3-default-templates.html
Edit
If you want to persist these values back on POST, you need to have an input element containing the values. In your case, the best way to do this would be to use a hidden field, for example:
#Html.HiddenFor(m => m.Username)
I'll use the famous NerdDinner as an example here.
I have a search page where the user can enter a search string and then see the result in a table below. The user can also add more results to the table, like this:
Search for dinners today and display in a table.
Search for dinners tomorrow and add the result to the table.
The table will now show dinners today and tomorrow.
The user is also able to remove dinners from the table by clicking on them, one by one.
I need to generate a pdf with the results in the table. Not like a print screen because the pdf has it's own layout. I just need the data in the table. Preferably in a list of Dinner models.
Right now I can generate a pdf from a list of Dinner models. But once I've printed them to the table and the user has manipulated it I don't know how to get it back to a list of Dinner models.
Another solution could be to keep the Id's hidden in the table and then do another search in the DB with the Id's from the table (after the user has manipulated it). At least then I would get the result in the form of a list of Dinners. But this seems redundant to me.
Has anyone had a similar problem and how did you solve it?
You could put the table inside an html <form> and on each row in addition to the label you could have a hidden field:
#model IEnumerable<Dinner>
#using (Html.BeginForm())
{
<table>
<thead>
<tr>
<th>Prop1</th>
<th>Prop2</th>
<th>Prop3</th>
</tr>
</thead>
<tbody>
#Html.EditorForModel()
</tbody>
</table>
<input type="submit" value="Export to PDF" />
}
and in the editor template:
#model Dinner
<tr>
<td>
#Html.DisplayFor(x => x.Prop1)
#Html.HiddenFor(x => x.Prop1)
</td>
<td>
#Html.DisplayFor(x => x.Prop2)
#Html.HiddenFor(x => x.Prop2)
</td>
<td>
#Html.DisplayFor(x => x.Prop3)
#Html.HiddenFor(x => x.Prop3)
</td>
</tr>
Now this form could be submitted to the following controller action:
public ActionResult GeneratePdf(IEnumerable<Dinner> dinners)
{
byte[] pdf = ...
return File(pdf, "application/pdf", "dinners.pdf");
}
You may also checkout the following blog post for managing a variable length list in order to keep input field names in sync for the binder when adding/removing elements.