Can somebody help me on the Lambda expression.
My ModelVM looks like :
namespace MReports.Models
{
public class FullDetailVM
{
public FullDetailVM()
{
DetailSet = new List<FullDetailSet>();
}
........
public List<FullDetailSet> DetailSet { get; set; }
}
public class FullDetailSet
{
public FullDetailSet(){ }
public string Mnum { get; set; }
public string Label { get; set; }
public string LabelValue { get; set; }
}
}
Data in the above model will be :
DetailSet[0] = {1,"MCity","LosAngeles"}
DetailSet[0] = {1,"MState","California"}
DetailSet[0] = {1,"MZip","90045"}
DetailSet[0] = {1,"MStreet","Cardiff"}
DetailSet[0] = {1,"MHouse No","1234"}
DetailSet[0] = {1,"MApt","1"}
View(Razor) :
#model MReports.Models.FullDetailVM
#if(Model != null)
{
<div class="row contentHeaderInfo">
<ul class="list-inline">
<li> City :
</li>
<li>
//Display LabelValue corresponding to Mcity
Model.DetailSet.select(LabelValue).Where(Label== "Mcity");
</li>
<li> State:
</li>
<li>
//Display LabelValue corresponding to MState
Model.DetailSet.select(LabelValue).Where(Label== "MState");
</li>
</ul>
</div>
}
Model.DetailSet.Where(x=>x.Label == "Mcity").Select(x=>x.LabelValue)
or if you have just one recors Label == Mcity
Model.DetailSet.SingleOrDefault(x=>x.Label == "Mcity").LabelValue
Lambda expressions can be used to create delegate types. I've found the easiest way to explain this to someone is to show them a list of items, such as your List<FullDetailSet> DetailSet, and ask them what items from that list do you want based on a specific condition?
If you wanted all the items with label "Dog" you would do something like this:
Model.DetailSet.Where(d => d.Label == "Dog").Select(d => d.Value);
This will go over the items in DetailSet and check if each item has a Label of "Dog". For lack of a better understanding on the correct terminology, you are iterating over that list and grabbing what you need based on your conditions. This is why I used d as the placeholder, to me it looks as though d is a singluar representation of DetailSet.
If you needed only one record from that DetailSet you would use Single over Where.
Model.DetailSet.Single(d => d.Label == "Dog").Select(d => d.Value);
If you didn't need just the Value of those records that met your conditions you can grab the entire list like this:
Model.DetailSet.Where(d => d.Label == "Dog").ToList();
You need to select one record using Single, then just get the property.
Model.DetailSet.Single(m => m.Label == "MState").LabelValue
Related
I have created a Model based on an EpiServer LinkItemCollection:
namespace ProjectX.Site.Models.Blocks
{
[SiteContentType(
GUID = "b9978bf2-f3da-4164-8fa2-3694c2ce0377",
AvailableInEditMode = false)]
[SiteImageUrl]
public class CustomTopNavigationItemtBlock : SiteBlockData
{
[CultureSpecific]
[MinItemCount(0)]
[MaxItemCount(2)]
[Display(Order = 10)]
public virtual LinkItemCollection CustomTopNavigationLinks { get; set; }
public override int WordCount
{
get => throw new System.NotImplementedException();
set => throw new System.NotImplementedException();
}
}
}
And I am trying to create a shared view for it:
#model CustomTopNavigationItemtBlock
#if (Model != null)
{
#foreach (var linkItem in Model)
{
<li>
<a class=""
href="#Url.PageUrl(linkItem.Href)"
target="#linkItem.Target"
title="#linkItem.Title"
tabindex="1"
data-toggle=""
role="button">
#linkItem.Text
</a>
</li>
}
}
Unfortunatley I don't understand what I am doing wrong.
Here, you are attempting to iterate over Model:
foreach (var linkItem in Model)
However, Model is of type CustomTopNavigationItemtBlock, which cannot be iterated using foreach, as it does not implement IEnumerable.
It seems that you are trying to loop over the CustomTopNavigationLinks property, which can be done like this:
foreach (var linkItem in Model.CustomTopNavigationLinks)
I have two lists in my page which display similar data, i used for-each to display the list. I it possible to display in a single list
My first List
<ul>
#foreach (var item in rpInfo)
{
<li data-id="#item.ID">
#item.PartyName
<ul>
<li> #item.spName </li>
</ul>
</li>
}
My Second List
<ul>
#foreach (var dRPs in deletedRpHistoryInfo)
{
<li data-id="#dRPs.ID">
#dRPs.PartyName
<ul>
<li>#dRPs.spName</li>
</ul>
</li>
}
</ul>
I need your help creating a list by combining the the two?
Thanks!
At its simplest you don't need two lists, you can simply have the two foreach statements inside the one list...
<ul>
foreach(...){
<li>....</li>
}
foreach(...){
<li>....</li>
}
</ul>
As an aside I'm not sure what value you get embedding the second ul inside the li either.
I take it your datatypes are similar but not identical, right? Do they inherit from the same parent - or is it maybe worth making them inherit from same parent(if it brings any other benefits). Then you can create new temporary list, typed with the common parent, and merge in both lists.
When foreaching a list with different datatypes in, when accessing a non-common datamember, you need to check what type the current item is.
Classes:
abstract internal class EmergencyEmployees
{
internal string Name { get; set; }
internal int Age { get; set; }
}
internal class Police : EmergencyEmployees
{
internal int PoliceLicence { get; set; }
}
internal class Firestarter : EmergencyEmployees
{
internal int FirestarterLicence { get; set; }
}
Program:
class Program
{
static void Main(string[] args)
{
var officers = new List<Police>();
var firestarters = new List<Firestarter>();
officers.Add(new Police { Name = "Kjell", Age = 45, PoliceLicence = 12345 });
officers.Add(new Police { Name = "Linda", Age = 42, PoliceLicence = 54321 });
firestarters.Add(new Firestarter { Name = "Arne", Age = 32, FirestarterLicence = 4322 });
firestarters.Add(new Firestarter { Name = "Anna", Age = 35, FirestarterLicence = 3322 });
var templist = new List<EmergencyEmployees>();
templist.AddRange(officers);
templist.AddRange(firestarters);
foreach(var ee in templist)
{
Console.WriteLine("Name: " + ee.Name);
Console.WriteLine("Age: " + ee.Age.ToString());
if(ee is Police)
{
var p = ee as Police;
Console.WriteLine("Police Licence: " + p.PoliceLicence.ToString());
}
if (ee is Firestarter)
{
var p = ee as Firestarter;
Console.WriteLine("Firestarter Licence: " + p.FirestarterLicence.ToString());
}
Console.WriteLine("--------------------");
}
}
}
Output:
Here is an article showing several ways that you can do this.
Given your example you could use the .Concat() as that way you keep the original data untouched and keep this all in the foreach loop. This will only work if the type used in both Lists are the same:
#foreach (var item in rpInfo.Concat(deletedRpHistoryInfo))
{
// do stuff
}
I have a HTML section with multiple list elements as such:
<li class="c-sidebar-nav-item c-sidebar-nav-dropdown #DropdownClass" #onclick="dropMenu">
<li class="c-sidebar-nav-item c-sidebar-nav-dropdown #DropdownClass" #onclick="dropMenu">
<li class="c-sidebar-nav-item c-sidebar-nav-dropdown #DropdownClass" #onclick="dropMenu">
The goal is that when one of the elements is clicked on, a new class c-show is added which then show the submenu's underneath.
My code in blazor to add this is:
#code{
bool MenuDroppedDown = true;
string DropdownClass => MenuDroppedDown ? "c-show" : "";
public async void dropMenu()
{
MenuDroppedDown = !MenuDroppedDown;
}
}
But the problem here is that once an element is clicked on, then c-show is added everywhere.
How can I have it so only the element where the onclick event occurred is affected?
Copy the code below into the Index component, add this amazing css class
.c-show {
background-color: red;
}
to the site.css located in the wwwroot folder, and run the code
<ul>
#foreach (var item in items)
{
<li class="c-sidebar-nav-item c-sidebar-nav-dropdown #item.DropdownClass" #onclick="#(() => item.MenuDroppedDown = !item.MenuDroppedDown)" >click me</li>
}
</ul>
#code{
List<LiTag> items = Enumerable.Range(1, 10).Select(i => new LiTag { ID = i }).ToList();
public class LiTag
{
public int ID { get; set; }
public bool MenuDroppedDown { get; set; }
public string DropdownClass => MenuDroppedDown ? "c-show" : "";
}
}
Please don't hesitate to ask questions, as this code is rather self-explanatory, I did not bother to explain what I was doing.
I have some tabs in bootstrap which has to be set as active depending on the action being hit. I have sub-tabs as well which has to be set as active depending on the action being hit as well.
Here is an image of how it looks like:
So when a sub-tab is being active the parent tab has to be active too.
So I thought to create a new Attribute where I save a pageId for each action and depending on the pageId on the view I can set it to active or not:
Here is the attribute:
public class YcoPageId : Attribute
{
public YcoPageId(int pageId)
{
PageId = pageId;
}
public int PageId { get; }
}
Here is the action:
[YcoPageId(1)]
public ActionResult Admin()
{
return View();
}
For the view I want to create an extension method to see if the tab and sub-tabs shall be active or not!
Here is my code:
public static bool IsActive(this HtmlHelper htmlHelper, params int[] ids)
{
var viewContext = htmlHelper.ViewContext;
var action = viewContext....
//How to get the YcoPageId attribute from here and see the Id
//Here i will test if ids contain id but dont know how to get it...
}
If you think adding an id for each page is bad idea I think for my case I will use this id for other purposes as well because it will be like identifier for a specific action...
So my question is how can I get the attribute YcoPageId for current action in my extension method ?
The view will look like this:
<li class="#(Html.IsActive(1, 4, 5... etc)? "active" : "")">
<a href="#url">
<div class="row text-center">
<div class="col-md-12">
<i class="fa #fontAwesomeIcon fa-4x" aria-hidden="true"></i>
<br/>#menuName
</div>
</div>
</a>
</li>
If there is any better idea how to solve this issue please go ahead!
Here is my solution to this problem:
First created a actionfilter attribute like below:
public class YcoPageIdAttribute : ActionFilterAttribute
{
public YcoPageIdAttribute(int pageId)
{
PageId = pageId;
}
public int PageId { get; }
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Result is ViewResult)
{
filterContext.Controller.TempData[DomainKeys.ViewPageId] = PageId;
}
else
{
throw new Exception("Only ViewResult has unique id");
}
base.OnActionExecuted(filterContext);
}
}
Then my action would look like this one:
[YcoPageId(1)]
public ActionResult Admin()
{
return View();
}
I created an extension method like below:
public static bool IsActive(this HtmlHelper htmlHelper, params int[] ids)
{
var viewContext = htmlHelper.ViewContext;
return viewContext.TempData.ContainsKey(DomainKeys.ViewPageId) &&
int.Parse(viewContext.TempData.Peek(DomainKeys.ViewPageId).ToString()).In(ids);
}
Since I know the id of an action now I have only to put the code as below in the view:
<li class="#(Html.IsActive(1)? "active" : "")">
<a href="#url">
<div class="row text-center">
<div class="col-md-12">
<i class="fa #fontAwesomeIcon" aria-hidden="true"></i>
<br /><small>#menuName</small>
</div>
</div>
</a>
</li>
I made another method on startup to check if I have actions with duplicated values like below:
public static void CheckForDuplicateActionId()
{
Assembly asm = Assembly.GetExecutingAssembly();
var controllerActionlist = asm.GetTypes()
.Where(type => typeof(Controller).IsAssignableFrom(type))
.SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly |
BindingFlags.Public))
.Where(m => !m.GetCustomAttributes(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute),
true).Any())
.Where(m => m.GetCustomAttribute<YcoPageIdAttribute>() != null)
.Select(
x =>
new
{
Controller = x.DeclaringType.Name,
Area = x.DeclaringType.FullName,
Action = x.Name,
ReturnType = x.ReturnType.Name,
Id = x.GetCustomAttribute<YcoPageIdAttribute>().PageId
})
.ToList();
var actionIds = controllerActionlist.Select(x => x.Id).ToList();
var actionIdsGrouped = actionIds.GroupBy(x => x).Where(x => x.Count() > 1).ToList();
if (!actionIdsGrouped.IsNullOrEmpty())
{
StringBuilder error = new StringBuilder("");
actionIdsGrouped.ForEach(actionId =>
{
var actions = controllerActionlist.Where(x => x.Id == actionId.Key);
actions.ForEach(a =>
{
error.Append(
$" | Id : {a.Id}, Action Name: {a.Action}, Controller Name : {a.Controller}, Location : {a.Area}. ");
});
});
var maxId = controllerActionlist.Max(x => x.Id);
error.Append(
"PLease consider changing the the duplicated id - Here are some options to choose from : Id {");
for (int i = 1, j = 1; i < maxId + 5; i++)
{
if (actionIds.Contains(i)) continue;
if (j < 5)
{
error.Append(i + ",");
j++;
}
else
{
error.Append(i + "}");
break;
}
}
throw new Exception(
$"There are more than one action duplicated with the same Id, The action data are as below : {error}");
}
}
Probably I will add all these data in database so I can identify an action from one id from database as well :)
Now it is working good.
If I understand correctly you are trying to create an id for each page/view and use it in the page/view to dynamically set css classes for setting menu tabs as active. If that is the case... Rather than trying to set the Ids in the Controller, how about creating a Shared View with only the following code - something like this....
In the View write the following Razor/C# code.
#{
var iPageId = 0
var sViewPath = ((System.Web.Mvc.BuildManagerCompiledView)ViewContext.View).ViewPath;
//for example
if (sViewPath.ToLower.IndexOf("admin") >= 0)
{
iPageId = 1;
}
else if (sViewPath.ToLower.IndexOf("dashboard") >= 0)
{
iPageId = 2;
}
else if (sViewPath.ToLower.IndexOf("vessels") >= 0)
{
iPageId = 3;
}
else if (sViewPath.ToLower.IndexOf("reports") >= 0)
{
iPageId = 4;
}
}
Render the Shared View in the primary view with the following snippet.
#Html.Partial("~/Views/Menu/_SharedViewName.cshtml")
Then you should be able to access the iPageId variable anywhere in the primary page/view(s) and set your CSS classes accordingly.
Dears,
Please could you help with below problem:
I want to render list of checkbox in my view.
#model IEnumerable<CFts.Models.CFModel>
...
#foreach (var test in ViewBag.CF_list)
{
if (test.Text != "" && test.Text != " ")
{
<div class="checkbox">
<label><input value="#test.Value" id="CF_list_" name="CF_list_" #(test.Selected == true ? "checked" : "") type="checkbox"> #test.Text</label>
</div>
}
}
OK, checkbox on the page.
CF_list generated in controller (SelectListItem)
But problem that - if send this form, at least one of checkboxes all time marked as selected. For example: 1. I selected two chekckboxed, send form - everything is OK. 2. I remove all ticks and send form - one of the checkbox (last clicked) indicated as selected.
Why?
CF_List is SelectListItem
Another question:
Please could you help me to understand very simple thing
I have model with my class:
public class VendorAssistanceViewModel
{
public string Name { get; set; }
public bool Checked { get; set; }
}
public partial class CSModel : IEntity
{
public CSModel()
{
VendorAssistances = new[]
{
new VendorAssistanceViewModel { Name = "DJ/BAND" },
new VendorAssistanceViewModel { Name = "Officiant" },
new VendorAssistanceViewModel { Name = "Florist" },
new VendorAssistanceViewModel { Name = "Photographer" },
new VendorAssistanceViewModel { Name = "Videographer" },
new VendorAssistanceViewModel { Name = "Transportation" },
}.ToList();
}
public IList VendorAssistances { get; set; }
I have view:
#model IEnumerable<CSTS.Models.CSModel>
... some html code...
and how here to show array of checkboxes from Model, using VendorAssistances ?
I know that this is very simple, I read a lot of docs, but still can not understand
Thank you!
Do not set the checked attribute, let the value attribute determine whether it is checked or not.
Change
<label><input value="#test.Value" id="CF_list_" name="CF_list_" #(test.Selected == true ? "checked" : "") type="checkbox">#test.Text</label>
To
<label><input value="#test.Value" id="c_" name="CF_list_" type="checkbox">#test.Text</label>
UPDATE: Just to make this easier to understand..
Do not use a SelectListItem for CF_List, use this instead. SelectListItem is used for drop down lists.
public class CFListCheckbox
{
public bool IsChecked { get; set; } // Add a property to know if the checkbox should be checked or not
public string Text { get; set; }
public object Value { get; set; } // Change as needed
}
In your GET action..
// Assign an ICollection<CFListCheckbox> to your ViewBag.CF_list
ICollection<CFListCheckbox> cfListCB = cfCollection.Select(r => new CFListCheckbox()
{
IsChecked = false,
Text = r.SomeProp,
Value = r.SomePropOrWhatever
}).ToList();
ViewBag.CF_list = cfListCB;
On your view, use the Html.Checkbox to create your checkboxes.
#foreach (var test in ViewBag.CF_list)
{
if (!string.IsNullOrWhiteSpace(test.Text))
{
<div class="checkbox">
<label>
#Html.Checkbox("CF_list_", test.IsChecked, new { Value = test.Value }) #test.Text
</label>
</div>
}
}
On your POST action, just set the ViewBag.ViewBag.CF_list in case your post fails and goes back to the view.
// Assign an ICollection<CFListCheckbox> to your ViewBag.CF_list
ICollection<CFListCheckbox> cfListCB = cfCollection.Select(r => new CFListCheckbox()
{
IsChecked = false,
Text = r.SomeProp,
Value = r.SomePropOrWhatever
}).ToList();
// Add logic to re-assign the IsChecked property for your ViewBag.CF_list
foreach(var entry in model.CF_list_)
{
CFListCheckbox item = cfListCB.FirstOrDefault(r => r.Text == entry.SomeProp && r.Value == entry.SomePropOrWhatever);
if(item != null)
{
item.IsChecked = true;
}
}
ViewBag.CF_list = cfListCB;
return View(model);
Please note that the sample code is just to give you an idea on what you can do. It is not absolute. Optimize it as needed.