MVC #HTML.Action in if statement causing issues - c#

I am working on a combined EDIT / New item page and want to check a list for items and then call HTML.Action() on a default value if .Count > 0 or loop through the list calling the same HTML.Action() to return the same partial view with different data.
Code so far that is not working:
#{
var list = #Model.MyList.FindAll(x=>x.somval == someotherval);
if (list.Count == 0)
{
#Html.Action("MyFunc", "MyController", new { MyData = Default.Value });
}
else
{
foreach(var Item in #Model.MyList)
{
#Html.Action("MyFunc", "MyController", new { MyData = Item.Data });
}
}
}
The issue is that the closing } for the first #Html.Action() is causing a compile error (expected ','). There has to be something simple that i am missing but I cannot seem to find the issue through googling.
EDIT Added full code.
EDIT: Thanks to Ashley Medway answer (posted before I edited to include the full code) I now have the following that is working
#{var list = #Model.MyList.FindAll(x=>x.somval == someotherval); }
#if (list.Count == 0)
{
Html.Action("MyFunc", "MyController", new { MyData = Default.Value });
}
else
{
foreach(var Item in list)
{
Html.Action("MyFunc", "MyController", new { MyData = Item.Data });
}
}
Thanks for your help.

You need to use # before if statment and remove # before foreach.
#if (Model.MyList.Count == 0)
{
#Html.Action("MyFunc", "MyController", new { MyData = Default.Value })
}
else
{
foreach (var Item in Model.MyList)
{
#Html.Action("MyFunc", "MyController", new { MyData = Item.Data })
}
}

The code that I would expect to work would look like this:
#if (Model.MyList.Count == 0)
{
#Html.Action("MyFunc", "MyController", new { MyData = Default.Value })
}
else
{
foreach(var Item in Model.MyList)
{
#Html.Action("MyFunc", "MyController", new { MyData = Item.Data })
}
}
FIX 1
An if statement in a razor view needs to start with an #, assuming that the if statement is not wrapped an another code block.
Change if (Model.MyList.Count == 0) to #if (Model.MyList.Count == 0)
FIX 2
Remove # from inside the foreach loop. As we are already inside a code block we do not need the # to access the model.
Change foreach(var Item in #Model.MyList) to foreach(var Item in Model.MyList)
FIX 3
Removing ; from the end of #Html.Action(...). Semicolons are not needed to terminate a line in the razor view. When using HTML helpers, it would still be needed in a some scenarios but the compiler will let you know :)
Leaving the semicolon ; in will not actually break your view but it will result in semicolons being added to your rendered HTML.

Related

Looping through a List<string[]> and get values of it

I am trying to display the values of this list of arrays, the problem is that the values are not displaying in the browser. I have the values of the list/arrays.
I don't know the problem or what's wrong with the syntax, any advice?
#{
List<string[]> validate_rules = new List<string[]>();
if (TempData["verification_errors"] != null)
{
validate_rules = (List<string[]>)TempData["verification_errors"];
}
}
#foreach (var item in validate_rules)
{
<label >#item[0].ToString() #item[2].ToString()</label>
}
You've surrounded the entire thing in a Razor Code Block. From the documentation:
Unlike expressions, C# code inside code blocks is not rendered.
I'm surprised it's even syntactically valid with the inline HTML inside a code block like that, unless there's an error that you're just ignoring. Remove the output from the code block. Something like this:
#{
List<string[]> validate_rules = new List<string[]>();
if (TempData["verification_errors"] != null)
{
validation_rules = (List<string[]>)TempData["verification_errors"];
}
}
#foreach (var item in validation_rules)
{
<p>#(item[0].ToString() + " " + item[2].ToString())</p>
}
The output can probably even be simplified to this:
#foreach (var item in validation_rules)
{
<p>#item[0] #item[2]</p>
}

Set selected value for DropDownListFor in controller does not work in razor view

I have this in my controller:
[Route("Checkout")]
public ActionResult Checkout()
{
var sb = new ShoppingBagViewModel();
sb.DestinationCountry = "Netherlands"; // I hoped that this was sufficient
sb.CountriesSl.Single(c => c.Text.Equals("Netherlands", StringComparison.InvariantCultureIgnoreCase)).Selected = true;
return View(sb);
}
Quick watch in Visual Studio confirmed that the CountriesSl (which is of type List<SelectListItem>) has a selected value. (netherlands)
This is my razor view:
#Html.DropDownListFor(m => m.DestinationCountry, Model.CountriesSl)
DestinationCountry is also a string prop in my viewmodel.
I know that there are a lot of similar questions, but I have looked at a lot of them and I just do not see it.
I also tried:
#Html.DropDownListFor(m => Model.DestinationCountry, Model.CountriesSl)
Please do not just give me the answer, but also explain what my mistake is.
edit to make clear what the problem is: I get a nice option list in my razor view, but there is no item "selected" just the first one. When I look at the generated html, there is no selected item too.
edit for Ric
public List<SelectListItem> CountriesSl
{
get
{
List<SelectListItem> _countries = HttpContext.Current.Cache["slCountries"] as List<SelectListItem>;
if (_countries == null)
{
_countries = new List<SelectListItem>();
foreach (string s in System.IO.File.ReadLines(System.Web.Hosting.HostingEnvironment.MapPath("~/tmpwrite/countries.csv")))
{
var tmp = s.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
_countries.Add(new SelectListItem() { Text = tmp[1], Value = tmp[0], Selected = false });
}
HttpContext.Current.Cache.Add("slCountries", _countries.OrderBy(c => c.Text).ToList(), null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(24, 0, 0), System.Web.Caching.CacheItemPriority.Normal, null);
}
return _countries;
}
}
DropDownListFor tries to automatically match the value of the receiving property in the provided enumeration. I also had problems with this in the beginning.
Instead provide any list of entities in the viewmodel. I usually use something like IDictionary<int, string>. Then create the dropdown like this:
Html.DropDownListFor(m=>m.DestinationCountry, new SelectList(Model.Countries, "Key", "Value"))
Then the SelectList will automagically set the correct option where its Key matches DestinationCoutry.

Show Unique values From Table in mvc

I want to show unique values so that only unique link will be shown. what can i do please tell as soon as possible
[Here i want to show unique Value but here is repeatetion of values][1]
My controller is this
public ActionResult AdminStudentAttendance()
{
AdmissionDBEntities obj = new AdmissionDBEntities();
var v = obj.AddTables.ToList();
return View(v);
}
My View is this
#model IEnumerable<AMSPractice.Models.AttendanceIn>
#using AMSPractice.Models;
<h2>ShowStudentAttendance</h2>
#foreach (var a in Model)
{
#Html.ActionLink(a.RollNo,"OneStudentDates","Attendance", new { nid = a.RollNo }, null) <br />
}
Inside of your foreach, it looks like the only property of the model you care about is the RoleNo. Explore something like this:
#foreach (var roleNo in Model.Select(m => m.RoleNo).Distinct())
{
#Html.ActionLink(roleNo,"OneStudentDates","Attendance", new { nid = roleNo }, null) <br />
}
You may need to play with that a bit, but basically you are appending a filter to Model to first give you only the RoleNo properties of each, then unique only.
Use Distinct to get unique values.
var uniques= Model.Select(x => x.RollNo).Distinct().ToList();
#foreach (var a in uniques)
{
#Html.ActionLink(a,"OneStudentDates","Attendance", new { nid = a }, null) <br />
}

razor html output result

I am trying to output the results in my #helpers code and the code looks like this
#helpers listfiles(String ID, String CNumber,){
foreach(Loopitem I in GetLoop("items")){
if(I.GetValue("userId") == ID){
<li>#I.GetValue("name")</li>
}else{
If(I.GetValue("userId") != ID){
<li>#I.GetValue("name")</li>
}
}
}
}
As a result I get all li elements but what I want is that if the statement is true it should wrap all the li elements in ul element and for the else statement it should wrap all the li in new UL element. Please help
One possible way by using two foreach, one for each user ID group :
#helpers listfiles(String ID, String CNumber,){
<ul>
foreach(Loopitem I in GetLoop("items").Where(o => o.GetValue("userId") == ID)){
<li>#I.GetValue("name")</li>
}
</ul>
<ul>
foreach(Loopitem I in GetLoop("items").Where(o => o.GetValue("userId") != ID)){
<li>#I.GetValue("name")</li>
}
</ul>
}
You mean something like this:
#helpers listfiles(String ID, String CNumber,){
var lstTrue = new List<>();
var lstFalse = new List<>();
foreach(Loopitem I in GetLoop("items")){
if(I.GetValue("userId") == ID)
lstTrue.Add(I);
else
lstFalse.Add(I);
}
if(lstTrue.Count()>0)
{
<ul> foreach(var I in lstTrue){<li>#I.GetValue("name")</li>}</ul>
}
if(lstFalse.Count()>0)
{
<ul> foreach(var I in lstTrue){<li>#I.GetValue("name")</li>}</ul>
}
}
Or you can make use of Lambda expression to reduce lines of code.

Checking Umbraco node length

I have a panel that is created and filled via a vacancy page I have created. Im doing it as follows:
#{
var root = CurrentPage.AncestorOrSelf(1);
var newsNode = root.Descendants("News").First();
var vacanciesNode = root.Descendants("Vacancies").First();
string shortenedSummary = string.Empty;
}
<ul>
#foreach (var vacancyItem in vacanciesNode.Descendants("Vacancy").Take(3).OrderBy("postDate desc"))
{
<p>here we are 2</p>
#vacanciesNode.Count().ToString()
<li>
<h4>#vacancyItem.jobTitle</h4> <span>Posted on #vacancyItem.postDate.ToString("dd/MM/yyyy")</span>
<p>
#if (vacancyItem.jobSummary.Length <= 182)
{
#vacancyItem.jobSummary
}
else
{
shortenedSummary = vacancyItem.jobSummary.Substring(0, 182) + "...";
#shortenedSummary
}
</p>
Read More..
</li>
}
</ul>
However, when there are no vacancy items, my list is empty. Should this be the case, I'm wanting it to read "sorry no vacancies just now" but I don't know how to check if my vacanciesNode has any items in it.
Could someone show me how I could achieve this?
Since the .Descendants() method returns a DynamicContentList (a collection) you can simply do a .Count() on the collection and check whether it's more than or equal to 1.
If there's more than 0 items in the collection, it's not empty.
So, what you need to do is surround your #foreach with an #if statement which checks on this, and an else statement after that prints whatever html you want to show if there's no vacancies
#if( vacanciesNode.Descendants("Vacancy").Take(3).OrderBy("postDate desc").Count() > 0) {
//Do foreach
}
else
{
//Write message about missing vacancies
}

Categories