MVC DisplayTemplate - change output for a given string value - asp.net-mvc

I currently have a view rendering a display page for a list of Employee entities.
The values returned from the database for the Gender property are a string value of "M" or "F" for the corresponding gender. I would like to be able to show string "Male" or "Female" in the view from the corresponding property value.
I've added the following logic to the Index.cshtml which is working.
#foreach (var item in Model)
{
<tr>
//... various <td>'s
#if (item.Gender == "M")
{
<td>Male</td>
}
else if (item.Gender == "F")
{
<td>Female</td>
}
}
I'm trying to move this to a Display Template, but cant get it working.
I've added the following code to the Views\Shared\DisplayTemplates\Gender.cshtml:
#model System.String
#if (Model.Gender == "M")
{
<td>Male</td>
}
else if (Model.Gender == "F")
{
<td>Female</td>
}
What is the best way to get this working?

You can add a partial view and call it like this in main view:
#foreach (var item in Model)
{
// other tds here
#Html.Partial("_Gender",item.Gender)
}
Create Partial view with name _Gender in the View >> Shared folder:
#model String
#{
Layout = null;
}
#if (Model== "M")
{
<td>Male</td>
}
else if (Model == "F")
{
<td>Female</td>
}
// or
<td>#(Model == "M" ? "Male" : "Female") </td>
It can also handle it in main view without creating partial view.
It can handle it in main view like this:
#foreach (var item in Model)
{
<tr>
//... various <td>'s
<td>#(item.Gender == "M" ? "Male" : "Female") </td>
</tr>
}

If you want it to work with a Display Template then you need to do something like this:
#foreach (var item in Model)
{
#Html.DisplayFor(model => item.Gender)
}
and in the View Model attach the attribute:
[UIHint("Gender")]
public string Gender { get; set; }
UIHint tells MVC which Display template to use. Otherwise by convention MVC will look for one called String.chtml

Related

Pass model to PartialAsync view (Razor, MVC)

I have AccountController.cs with below action:
[HttpGet]
[AllowAnonymous]
public IActionResult Register()
{
ViewBag.Registration = GetRegistration();
return View();
}
ViewBag.Registration contains 2 elements and it's ok.
Then I got Registration.cshtml view:
#model Registration <!-- this model I'm using for other form -->
#{
Layout = "_Layout";
}
<!-- some code -->
#await Html.PartialAsync("AllRegistered")
and AllRegistered.cshtml where data from ViewBag.Registration should be displayed:
#model IEnumerable<Registration>
<table>
<tr>
<th>#Html.DisplayNameFor(m => m.Email)</th>
<th>#Html.DisplayNameFor(m => m.City)</th>
</tr>
#if (Model != null && Model.Count() != 0)
{
#foreach (Registration registration in Model)
{
<tr>
<th>#Html.DisplayFor(m => registration.Email)</th>
<th>#Html.DisplayFor(m => registration.City)</th>
</tr>
}
}
</table>
But nothing is generated into view, Model I think is empty.
The PartialAsync method contains an overload which includes the model:
Html.PartialAsync(string partialViewName, TModel model)
You should include the IEnumerable<Registration> (the partial view's model) in that helper.
If GetRegistrations() is returning that IEnumerable, you would define the partial view like this:
#await Html.PartialAsync("AllRegistered", (List<Registration>)ViewBag.Registration)
While Nathan's answer is perfectly correct, it would be more appropriate for this to be a view component. The fact that you want to display all registrations is a view detail that has nothing to do with the purpose of this action. As such, having the action be responsible for retrieving data requires it to have knowledge it doesn't need and shouldn't have.
Instead, add a class like:
public class AllRegistrationsViewComponent : ViewComponent
{
private readonly RegistrationsService _service;
public AllRegistrationsViewComponent(RegistrationService service)
{
_service = service;
}
public async Task<IViewComponentResult> InvokeAsync()
{
// logic behind `GetRegistrations()` here
return View(registrations);
}
}
The reference here to RegistrationsService is just whatever means you're using to retrieve your registrations, to show how to inject that into the component. This might be your context or something else entirely.
Then, create the view Views/Components/AllRegistrations/Default.cshtml with:
#model IEnumerable<Registration>
<table>
<tr>
<th>#Html.DisplayNameFor(m => m.Email)</th>
<th>#Html.DisplayNameFor(m => m.City)</th>
</tr>
#if (Model != null && Model.Count() != 0)
{
#foreach (Registration registration in Model)
{
<tr>
<th>#Html.DisplayFor(m => registration.Email)</th>
<th>#Html.DisplayFor(m => registration.City)</th>
</tr>
}
}
</table>
The AllRegistrations part of the path is based on the name of the view component, without the ViewComponent part, so if you name it differently, adjust here as well.
Finally, in your view:
#await Component.InvokeAsync("AllRegistrations")
Then, your action can just focus on its actual purpose:
[HttpGet]
[AllowAnonymous]
public IActionResult Register()
{
return View();
}

Passing data base info from controller to view in .NET MVC

Hello I'm trying to pass some database info from my controller to my view, but don't find the best way to do it. I'm populating the model in my controller, but I need to populate those values from database. I have a class called DataAccess which is the one that contains all my queries but not sure where I should put the logic to populate. I would say a for loop in my controller to populate the values, but seems to fail since I'm declaring the SchedulerViewModel there
The idea is having my values next to a radio button, so when selecting a radio button, I can "detect" the value and do something with that option....any suggestion would be appreciated...
My model:
public class SchedulerViewModel
{
public string theValue { get; set; }
public SelectListItem[] Items { get; set; }
}
My Controller:
public ActionResult Scheduler()
{
//DataAccess dataAccess = new DataAccess();
//for loop here???
var model = new SchedulerViewModel
{
Items = new[]
{
new SelectListItem { Value = "U", Text = "USA" }
}
};
return View(model);
}
My view:
#using (Html.BeginForm())
{
for (int i = 0; i < Model.Items.Count(); i++)
{
#Html.RadioButtonFor(x => x. theValue, Model.Items[i].Value, new { id = "item_" + i })
#Html.Label("item_" + i, Model.Items[i].Text)
<br />
}
}
Ideally you would have a service class that handles your database access. You shouldn't directly invoke the data layer from the controller, although nothing prevents you from doing it. For simplicity, I'm just putting calling the data access directly in the controller. The idea is that you need to return a collection of data, here an IEnumerable, in the View at the controller level so that the View can display this data.
Controller:
[HttpGet]
public ActionResult Index()
{
KnowledgeBaseEntities context = new KnowledgeBaseEntities();
IEnumerable<ISSUE> issues = context.ISSUES;
if(issues == null)
{
return HttpNotFound();
}
return View(issues);
}
View:
As you can see I'm referencing the collection of data that I'm expecting from the controller.
#model IEnumerable<ISSUE>
In this case it's an IEnumerable just like I had in the controller. Then you'll notice I'm referencing a Model object when I iterate the model.
#foreach (var item in Model)
Then I'm looping through each row of the model in order to add table rows to the table. Because we're using Model Binding from the Entity Framework. We're using Razor Syntax. You also notice I'm using Action Links for each row in the last column. This allows me to Edit, Delete or provide Details for a row of data. However, I will need to invoke another Controller Action for that. For example, you'd have an Edit controller action method that returns a single ISSUE to an Edit View.
#model IEnumerable<ISSUE>
#{
ViewBag.Title = "Knowledge Base Issues";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2 class="line">All Issues</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="flat">
<tr>
<th>#Html.DisplayNameFor(model => model.KEYWORDS)</th>
<th>#Html.DisplayNameFor(model => model.SUBJECT)</th>
<th>#Html.DisplayNameFor(model => model.DATE_ENTERED)</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>#Html.DisplayFor(modelItem => item.KEYWORDS)</td>
<td>#Html.DisplayFor(modelItem => item.SUBJECT)</td>
<td>#Html.DisplayFor(modelItem => item.DATE_ENTERED)</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.ISSUE_ID }) |
#Html.ActionLink("Details", "Details", new { id=item.ISSUE_ID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.ISSUE_ID })
</td>
</tr>
}

foreach statement cannot operate because does not contain a public definition for 'GetEnumerator'

I build a solution has 4 layers
1-One Solution (Data Access layer) has multi (DALs) from diffrent DBs.
2-Data Store(access all DALs).
3-Business Layer BL(haslogicalmethods)
4-Presentation layer (MVC4).
the problem is I want call a list search methods in DAL(Establishment) through BLL with Para Name to search it , and want to show the result in View in PL.
the EstController
public ActionResult Index(string Name)
{
if (Name != null)
{
IList list = BLL.Establishment_Serv.getEstablishmentByName(Name.ToUpper());
return View(list);
}
return View();
}
and Est/Index View
#using (Html.BeginForm("Index" ,"Est",FormMethod.Get))
{
<p>
Find by name: #Html.TextBox("Name")
<input type="submit" value="Search" />
</p>
}
<table>
#foreach (var item in Model)
{
<tr>
<td>#Html.DisplayFor(modelItem => item.Id)</td>
<td>#Html.DisplayFor(modleItem => item.Name)</td>
</tr>
}
</table>
and I face an error in foreach statement.And if there a best approach to doing it HINT me please.
Have you put this inside your view:
#model IEnumerable<YourModel>
if your list is null then you will get error
public ActionResult Index(string Name)
{
var list=new List<YourModelName>();
if (Name != null)
{
list = BLL.Establishment_Serv.getEstablishmentByName(Name.ToUpper());
return View(list);
}
else {
return View(list);
}
}

MVC Razor, add if statement to foreach loop

I'm trying to add data from my model to a table with razor. My problem is that i want an if statement to decide what class the tagg should be and i can't get this to work.
When i add the if i get the following error when i run the code
The foreach block is missing a closing "}" character
How should i add the if statement? This is my current code
#{
var counter = 0;
}
#foreach (var item in Model)
{
if(item.status == "Active") {
<tr>
}
else {
<tr class="danger">
}
<td>#counter</td>
<td>#item.FirstName #item.LastName</td>
<td>#item.Email</td>
<td>#item.PhoneNumber</td>
<td>Ändra</td>
<td>Inaktivera</td>
</tr>
counter++;
}
MVC should detect html tags and render those out, however it seem this doesnt always work.
In between the curly brackets, try adding a tag
eg:
{
<text>
your html
</text>
}
or
if you just adding the class try something like:
<tr #(item.status == "Active" ? String.Empty : "class=\"danger\"" )>
try below code.
#{
var counter = 0;
}
#foreach (var item in Model)
{
if(item.status == "Active") {
<text> <tr> </text>
}
else {
<text><tr class="danger"></text>
}
<td>#counter</td>
<td>#item.FirstName #item.LastName</td>
<td>#item.Email</td>
<td>#item.PhoneNumber</td>
<td>Ändra</td>
<td>Inaktivera</td>
</tr>
counter++;
}
MVC detect HTML tags. So it will not add if statement like that.
you can not use <text><text> also.
You need to check condition in <tr> tag itself. See given result below.
#{
var counter = 0;
}
<table>
#foreach (var item in Model)
{
<tr #(item.status=="Active" ? String.Empty : "class=\" danger\"")>
<td>#counter</td>
<td>#item.FirstName #item.LastName</td>
<td>#item.Email</td>
<td>#item.PhoneNumber</td>
<td>Ändra</td>
<td>Inaktivera</td>
</tr>
counter++;
}
</table>
You can add extension method that take bool or string depend on your needs
public static class HtmlHelpExtention
{
public static string IsChecked(this IHtmlHelper htmlHelper,bool IsCheck, string className)
{
return IsCheck? className:"";
}
}
and then use it in the view
<tr class="#Html.IsChecked(item.IsGift,"teal accent-3")">
using this method will give you the ability to use multiple classes
Love Pandey solution works for me, but only for one class name. For more than one class name browser interpret second name as separate attribute. My modification for it is as below:
#{
var counter = 0;
}
<table>
#foreach (var item in Model)
string className = item.status=="Active" ? String.Empty : "item second-class-name";
{
<tr class="#className">
<td>#counter</td>
<td>#item.FirstName #item.LastName</td>
<td>#item.Email</td>
<td>#item.PhoneNumber</td>
<td>Ändra</td>
<td>Inaktivera</td>
</tr>
counter++;
}
</table>
You cannot use tag twice in a code block.
If you encounter problem because this limitation, put the second textbox as a string and then display it using html helper.
#{
int loop=0;
string HtmlBlock = "<table><tr><td style='font-weight:bold'>Lorem Text</td></tr></table>";
}
#foreach(var itemz in Mode.List){
If(loop ==3){ Html.Raw(HtmlBlock ); }
<text>itemz.Name Itemz.NIP</text>
loop++;
}

The model item passed into the dictionary is of type 'System.Data.Entity.DynamicProxies.Objt

The model item passed into the dictionary is of type 'System.Data.Entity.DynamicProxies.Donemler_8A34F5A0E6AB4F6429B22B8E4A5B0CDD80C5DCEA6C183E8068EDB99DF7FA8263', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[Anket.Data.DomainModel.Donemler]'.
Here is my code:
Controller part
public ActionResult _DonemGetir(int id)
{
var donem = donemService.Bul(id);
return PartialView(donem);
}
Service Class
public Donemler Bul(int id)
{
return db.Donem.Find(id);
}
View Part
#model IEnumerable<Anket.Data.DomainModel.Donemler>
#{
foreach (var item in Model)
{
#Html.DisplayFor(model => item.donem )
}
}
Id value in Controller( _DonemGetir(int id) ) comes from another view and those View Codes :
#model IEnumerable<Anket.Data.DomainModel.Anketler>
#foreach(var item in Model)
{
<tr>
<td class="nameRecord">
#Html.Action("_DonemGetir", "Ortak", new { id = item.ID })
</td>
</tr>
}
</table>
_DonemGetir View :
#model IEnumerable<Anket.Data.DomainModel.Donemler>
#{
foreach (var item in Model)
{
#Html.DisplayFor(model => item.donem )
}
}
I have two tables:
Anketler and Donemler
Anketler table has :
ID(PK) - name - and donem_id (FK)
Donemler table has :
ID(PK) - name
I want to fetch data from Anketler and I do not want to fetch donem_id as an integer. I need it's name from Donemler table. I tried to do this with these codes.
I fixed the problem
I changed _DonemGetir View like this
#model Anket.Data.DomainModel.Donemler
#{
#Html.DisplayFor(model => model.donem)
}

Resources