check if a node has a property - asp.net-4.0

I'm trying to check if a certain node has a property "footerTextTitle" by:
#foreach (var nodeLink in footerTop.ChildrenAsList.Where(n => n.GetProperty("footerTextTitle").IsNull() == true))
{
<li><a href='#nodeLink.GetProperty("footerLinkUrl").Value.ToString()'>#nodeLink.GetProperty("footerLinkTitle").Value.ToString()</a></li>
}
and getting a "Object reference not set to an instance of an object." error.
How can I do this ?
Thanks.

To check if a property exists simply check if the property is null like below
#foreach (var nodeLink in footerTop.ChildrenAsList.Where(n => n.GetProperty("footerTextTitle") == null))
{
<li><a href='#nodeLink.GetProperty("footerLinkUrl").Value.ToString()'>#nodeLink.GetProperty("footerLinkTitle").Value.ToString()</a></li>
}
P.S. To debug, append this to the url
http://www.example.com/page.aspx?umbDebugShowTrace=true

Related

There is no ViewData item of type 'IEnumerable<SelectListItem>' that has the key 'BranchQuickChange'

I've been on this error for a while and the ienumerable object is blocking can someone pls help me the error is in the description.
HTML:
#model IEnumerable<DatabaseDAL.Models.WAGTripHdr>
<script type="text/javascript" src="~/Scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$("select#BranchQuickChange").change(function () {
var branchName = $("select#BranchQuickChange option:selected").text();
alert(branchName);
window.location.href = '#Url.Action("QuickBranchChange", "TripSheets")?branchName=' + branchName;
});
</script>
<div class="row-fluid">
<div class="span4" style="margin-top: 15px">
#if (User.IsInRole("Administrator") || User.IsInRole("SuperUser"))
{
<strong>Quick Switch</strong> #Html.DropDownList("BranchQuickChange",ViewBag.CompanyList as SelectList)
}
</div>
Controller:
{
List<WAGBranch> listWagBranch = WAGBranchRepository.GetAllBranches(CompanyEnum.WAG).OrderBy(i => i.BRName).ToList();
List<string> listCompany = new List<string>();
foreach (WAGBranch branch in listWagBranch)
{
listCompany.Add(branch.BRName); // + " - " + branch.Branch);
}
//listCompany.Insert(0, "WAG HEAD OFFICE - WAG");
if ((string)selected == "") selected = null;
ViewBag.CompanyList = new SelectList(listCompany, selected);
}
Model:
[TableNameAttribute("WAGTripHdr")]
public class WAGTripHdr : SQLSelectUpdateInsertHelper
{
public string DebName { get; set; }
}
Waiting for some advices.
That error usually occurs when the collection passed to DropDownListFor is null. As a fallback, the helper tries to find the options in the ViewBag under a member named after the property, i.e. ViewBag.BranchQuickChange. When it fails to find anything usable there, as well, it gives up and you get the exception you reference.
That said, it appears you are in fact setting ViewBag.CompanyList in your action. Additionally, it is being set to a SelectList instance, so casting it back to SelectList in the view as you're doing should materialize the value. The only thing I can think of is that perhaps a different action than the one you've posted here is being loaded. In particular, if you have GET and POST versions of this action, make sure that both set ViewBag.CompanyList. It's possible you only added that line to one and not the other.

Create a method/function to use within a view

How can we write a function to use in a *.cshtml page. We used to be able to use #helper or #function within the view. How do we do this? For instance, I would like to write a recursive function to show all configuration values. How could I do this?
<dl>
#foreach(var k in config.GetSubKeys())
{
<dt>#k.Key</dt>
<dd>#config.Get(k.Key)</dd>
#* TODO How can we make this a helper function/recursive? *#
#foreach(var sk in config.GetSubKey(k.Key).GetSubKeys())
{
<dt>#sk.Key</dt>
<dd>#config.Get(sk.Key)</dd>
}
}
</dl>
I imagine that we need to add a dependency in project.json and then opt-in to using it in Startup.cs.
Quick and dirty using razor views assuming your view component provides a recursive model.
Component view:
#model YourRecursiveDataStructure
<ul class="sidebar-menu">
<li class="header">MAIN NAVIGATION</li>
#foreach (var node in Model.RootNodes)
{
#Html.Partial("~/YourPath/RenderElement.cshtml", node)
}
</ul>
Render element in a view :
#model YourRecursiveNode
<li>
<a href="#Model.Href">
<span>#Model.Display</span>
</a>
#Html.Partial("~/YourPath/RenderChildren.cshtml", Model)
</li>
Then loop node's children in another view:
#model YourRecursiveNode
#if (Model.HasChildren)
{
<ul>
#foreach (var child in Model.Children)
{
#Html.Partial("~/YourPath/RenderElement.cshtml", child)
}
</ul>
}
Referring to a few design discussions that we only have glimpses of online, #helper was removed for design reasons; the replacement is View Components.
I'd recommend a View Component that looked like the following:
public class ConfigurationKeysViewComponent : ViewComponent
{
private readonly IConfiguration config;
public ConfigurationKeysViewComponent(IConfiguration config)
{
this.config = config;
}
public IViewComponentResult Invoke(string currentSubKey = "")
{
return View(new ConfigurationData
{
Key = currentSubKey,
Value = config.Get(currentSubKey),
SubKeys = config.GetSubKey(currentSubKey).GetSubKeys().Select(sk => sk.Key)
});
}
}
Your ViewComponent's View would then be relatively simple:
<dt>#Model.Key</dt>
<dd>#config.Get(Model.Key)</dd>
#foreach (var sk in Model.SubKeys)
{
#Component.Invoke("ConfigurationKeys", sk)
}
You could then invoke it from your root view as follows:
#Component.Invoke("ConfigurationKeys")
Disclaimer: I wrote this in the SO editor, there may be compiler errors. Also, I'm uncertain if View Components support default parameters - you may need to add a default "" to the root view's call to the view component.
Alternatively, if this is just debugging code, you can unwrap your recursiveness by using a Stack<>.

Multiple radio button groups in MVC 4 Razor

I need to have multiple radio button groups in my form like this:
I know it's simply done by specifying the same "name" html attribute for each group.
HOWEVER
MVC doesn't let you specify your own name attribute when using html helper like this:
#Html.RadioButtonFor(i => item.id, item.SelectedID, new { Name = item.OptServiceCatId })
Because it looks at each tag's "name" attribute (not "id") to map/bind the form to the model which the controller receives, etc.
Some said that specifying each with the same "GroupName" attribute will solve the problem, but it didn't work either.
So, is there any way which works ?
EDIT:
Here's my view (simplified):
#model Service_Provider.ViewModels.SelectOptServicesForSubServiceViewModel
#foreach (var cat in Model.OptServices)
{
//A piece of code & html here
#foreach (var item in cat.OptItems.Where(i => i.MultiSelect == false))
{
#Html.RadioButtonFor(i => item.id, item.SelectedID, new { GroupName = item.OptServiceCatId })
<br />
}
}
NOTE:
My model is a List<OptServices>:
public List<OptServices> Cats {get; set;}
And OptServices has a List of OptItems inside:
public class OptServices
{
//a few things
public List<OptItems> Items {get; set;}
}
all you need is to tie the group to a different item in your model
#Html.RadioButtonFor(x => x.Field1, "Milk")
#Html.RadioButtonFor(x => x.Field1, "Butter")
#Html.RadioButtonFor(x => x.Field2, "Water")
#Html.RadioButtonFor(x => x.Field2, "Beer")
Ok here's how I fixed this
My model is a list of categories. Each category contains a list of its subcategories.
with this in mind, every time in the foreach loop, each RadioButton will have its category's ID (which is unique) as its name attribue.
And I also used Html.RadioButton instead of Html.RadioButtonFor.
Here's the final 'working' pseudo-code:
#foreach (var cat in Model.Categories)
{
//A piece of code & html here
#foreach (var item in cat.SubCategories)
{
#Html.RadioButton(item.CategoryID.ToString(), item.ID)
}
}
The result is:
<input name="127" type="radio" value="110">
Please note that I HAVE NOT put all these radio button groups inside a form. And I don't know if this solution will still work properly in a form.
Thanks to all of the people who helped me solve this ;)
I fixed a similar issue building a RadioButtonFor with pairs of text/value from a SelectList. I used a ViewBag to send the SelectList to the View, but you can use data from model too. My web application is a Blog and I have to build a RadioButton with some types of articles when he is writing a new post.
The code below was simplyfied.
List<SelectListItem> items = new List<SelectListItem>();
Dictionary<string, string> dictionary = new Dictionary<string, string>();
dictionary.Add("Texto", "1");
dictionary.Add("Foto", "2");
dictionary.Add("VĂ­deo", "3");
foreach (KeyValuePair<string, string> pair in objBLL.GetTiposPost())
{
items.Add(new SelectListItem() { Text = pair.Key, Value = pair.Value, Selected = false });
}
ViewBag.TiposPost = new SelectList(items, "Value", "Text");
In the View, I used a foreach to build a radiobutton.
<div class="form-group">
<div class="col-sm-10">
#foreach (var item in (SelectList)ViewBag.TiposPost)
{
#Html.RadioButtonFor(model => model.IDTipoPost, item.Value, false)
<label class="control-label">#item.Text</label>
}
</div>
</div>
Notice that I used RadioButtonFor in order to catch the option value selected by user, in the Controler, after submit the form. I also had to put the item.Text outside the RadioButtonFor in order to show the text options.
Hope it's useful!
I was able to use the name attribute that you described in your example for the loop I am working on and it worked, perhaps because I created unique ids? I'm still considering whether I should switch to an editor template instead as mentioned in the links in another answer.
#Html.RadioButtonFor(modelItem => item.Answers.AnswerYesNo, "true", new {Name = item.Description.QuestionId, id = string.Format("CBY{0}", item.Description.QuestionId), onclick = "setDescriptionVisibility(this)" }) Yes
#Html.RadioButtonFor(modelItem => item.Answers.AnswerYesNo, "false", new { Name = item.Description.QuestionId, id = string.Format("CBN{0}", item.Description.QuestionId), onclick = "setDescriptionVisibility(this)" } ) No
You can use Dictonary to map
Assume Milk,Butter,Chesse are group A (ListA)
Water,Beer,Wine are group B
Dictonary<string,List<string>>) dataMap;
dataMap.add("A",ListA);
dataMap.add("B",ListB);
At View , you can foreach Keys in dataMap and process your action

Form submission for mvc model enumerable using editor template

I have an editor template for my model view ViewSetup. My view to use template is simplified as
#model IEnumerable<ViewSetup>
#Html.EditorFor(s => s)
My ViewSetup editor template has form submission like below:
using (Ajax.BeginForm("Edit", new AjaxOptions() { HttpMethod = "Post" }))
{
#Html.HiddenFor(p => p.TradingPartner.ID)
<input type="submit" value="Save" />
}
So basically i need a form to be submitted for each element of the Enumerable. But I'm facing a problem on form submission. My controller to process post is:
public ActionResult Edit(ViewSetup formDataSent)
{
formDataSent.Save();
}
As per default model binding I'm getting null for TradingPartner property since the name in the html is :
<input name="[0].TradingPartner.ID" type="hidden" value="1"/>
What I need is to submit only the ViewSetup object on each element instead of an array. If I can get the index part in the name removed that could work for me. But I'm not sure how to get just the ViewSetup object on form submission.
I bet that if you base your editor on one item instead of a list of items then you would gain more flexibility.
#model IEnumerable<ViewSetup>
#foreach (var item in Model)
{
#Html.EditorFor(modelItem => item.TradingPartner)
}
I had the same issue, what resolved it for me was this:
#foreach (var item in Model)
{
#Html.EditorFor(modelItem => item.TradingPartner, null, "")
}
The third property of the EditorFor being blank will get rid of the "[0]" from your objects.

Duplicates on runtime MVC4 Entity Framework

I get this strange "error". When i run my app (edit action i.e update) i get duplicate values stored in my dB. If i use the debugger, step by step, its working (no duplicates)...
It's a Many-to-Many Relationship so don't bother the Courses NULL value in the images, just trying to figure things out...
All Help is appreciated!
[HttpPost]
public ActionResult Edit(CourseStudentViewModel model)
{
var course = db.Courses
.Where(c => c.Id == model.CourseId)
.Single();
if (ModelState.IsValid)
{
course.Name = model.CourseName;
course.Description = model.CourseDescription;
course.Students = model.Students;
if(course.Id != 0) {
db.Entry(course).State = System.Data.EntityState.Modified;
}
else {
db.Courses.Add(course);
}
db.SaveChanges();
return RedirectToAction("Index");
}
//modelstate not valid, display form
return View(model);
}
I get my viewModel back. All good.
My Old values from dB. I want to update this data. So everything is still good...
My old values are updated to my new Values. Great!
Ok everything works great IF I step with debugger like this. But if i run the app i will get duplicates.... Anyone?
New content:
My Edit-view
#model ValueInjecter.Web.Models.CourseStudentViewModel
#{
ViewBag.Title = "Edit"; }
Edit Course
#using (Html.BeginForm()) {
#Html.HiddenFor(c => Model.CourseId)
#Html.LabelFor(c => Model.CourseName)
#Html.EditorFor(c => Model.CourseName)
#Html.LabelFor(c => Model.CourseDescription)
#Html.EditorFor(c => Model.CourseDescription)
</div>
<hr />
<h2>Students</h2>
<div class="editor-field">
#for (int i = 0; i < Model.Students.Count(); i++)
{
<div style="border: dotted 1px; padding: 5px; margin: 10px;">
#Html.HiddenFor(s => s.Students[i].Id)
#Html.LabelFor(s => s.Students[i].Name[i + 1])
#Html.EditorFor(s => s.Students[i].Name)
</div>
}
</div>
<p>
Number of Students:
<b>#Html.DisplayFor(s => Model.StudentCount)</b>
</p>
<hr />
<p>
<input type="submit" value="Save" />
</p> }
It probably works in the debugger because by inspecting course.Students collection in a property watch window you trigger actually a second database query (after the query that loads the course) due to lazy loading of the Students collection. (Your Course.Students collection is most likely declared as virtual.) If you run without debugger no lazy loading occurs and course.Students stays empty.
You can force that the course.Students collection is always loaded by using eager loading instead of lazy loading (which also saves the second database roundtrip):
var course = db.Courses
.Include(c => c.Students)
.Where(c => c.Id == model.CourseId)
.Single();
Honestly I have no clue why your code works correctly with the loaded collection (in the debugger) and why it works at all. Assigning a complete detached collection like this: course.Students = model.Students, and then just setting the state of the parent to Modified is normally not enough to update a child collection.
But I see "ValueInjecter" in your screenshots. Maybe there is some automatic mapping magic happening that does (accidentally?) the right thing to get a working update.
Ok I finally figured out the solution of my problem. Of course much easier than first thought.
[HttpPost]
public ActionResult Edit(CourseStudentViewModel model)
{
if (ModelState.IsValid)
{
var course = db.Courses.Find(model.CourseId);
course.Name = model.CourseName;
course.Description = model.CourseDescription;
if(model.Students != null)
{
foreach (var item in model.Students)
{
db.Entry(item).State = System.Data.EntityState.Modified;
}
}
if(course.Id != 0) {
db.Entry(course).State = System.Data.EntityState.Modified;
}
else {
db.Courses.Add(course);
}
db.SaveChanges();
return RedirectToAction("Index");
}
//modelstate not valid, display form
return View(model);
}
Still using the view ive pasted above.