Nested operations with Razor View Engine - c#

I cannot figure out how to do "nested" operation in Razor. For example how to use IF inside FOREACH. VisualStudio throws compile-time error on following block, saying "Invalid expression term 'if' "
#foreach (var document in Model) {
#if (document.Item.Count > 0) {
<div>
#MvcHtmlString.Create(document.Items[0].ContentPresenter)
</div>
}
}

Don't you just need to drop the # off the #if and make it:
#foreach (var document in Model) {
if (document.Item.Count > 0) {
<div>
#MvcHtmlString.Create(document.Items[0].ContentPresenter)
</div>
}
}
Sorry I haven't worked with Razor but isn't its selling point the automatic switching back and forth between code and HTML based on context?

Related

EditorTemplate inheritance - is there a way

EditorTemplates are great since they allow some kind of "polymorphism" in razor views. But I am missing one "brick" to complete the polymorphism support:
Can an EditorTemplate for a special type inherit from the EditorTemplate for the general type?
Long version:
Given
class SpecialChild : GeneralChild { }
class Parent
{
GeneralChild AGeneralChild { get; set; }
SpecialChild ASpecialChild { get; set; }
}
and two editor templates
#* GeneralChild.cshtml *#
#model GeneralChild
<span>GeneralChild</span>
#* SpecialChild.cshtml *#
#model SpecialChild
<span>SpecialChild is a</span> <span>GeneralChild</span>
What I get (which is why I call it "polymorphism") is:
#* Index.cshtml *#
#Html.EditorFor(m => m.AGeneralChild)
// prints "<span>GeneralChild</span>", however
#Html.EditorFor(m => m.ASpecialChild)
// prints "<span>SpecialChild is a</span> <span>GeneralChild</span>"
That is, even though SpecialChild is a GeneralChild and there is a template for GeneralChild, it auto-selects the SpecialChild.cshtml template. Furthermore, if I remove that template, it falls back to the GeneralChild.cshtml template. In other words, it is possible to reuse a general template or to override it if necessary.
Now for what I would really like:
I would like to reuse the GeneralChild.cshtml template to define the SpecialChild.cshtml template, like a "base method" call in C#. In pseudo-code:
#* SpecialChild.cshtml *#
baseEditorFor()
#section SpecificPart
{
<span>SpecialChild is a </span>
}
#* GeneralChild.cshtml *#
#Html.RenderSection("SpecificPart") <span>GeneralChild</span>
Is something like that supported?
What I have tried so far:
GeneralChild.cshtml:
#model GeneralChild
#{
var extend = ViewData.ContainsKey("Extend")
? (MvcHtmlString)ViewData["Extend"]
: null;
}
#if (extend != null) { #extend }
<span>GeneralChild</span>
SpecificChild.cshtml:
#model SpecialChild
#Html.EditorFor(
m => m, // call editor for my model
"GeneralChild", // but call "base" instead of "this"
new
{
// Hand the HTML to insert as ViewData parameter
Extend = new MvcHtmlString("<span>SpecialChild is a </span>")
})
Unfortunately, #Html.EditorFor(m => m) does not do anything. That makes sense because m => m is not the same expression as the original m => m.ASpecialChild.
I thought I could build up the expression tree by hand, but then I realized that the type arguments within the editor template are (of course) different from the ones in the Index.cshtml. #Html in the original call is typed <Parent> whereas within the template it is <SpecialChild>.
Then I tried another approach which is the closest I got so far:
Within the Index.cshtml I define a razor helper:
#helper SpecialChildEditorFor(Expression<Func<Parent,SpecialChild>> expression)
{
#Html.EditorFor(
expression,
"GeneralChild",
new { Extend = new MvcHtmlString("<span>SpecialChild is a </span>") })
}
Then I call this instead of EditorFor:
#SpecialChildEditorFor(m => m.ASpecialChild)
But of course this lacks the entirety of the the initially mentioned advantages - I can't simply drop this snippet in the EditorTemplates directory, thus "overriding" the GeneralChild.cshtml template. Also, it needs to be explicitly called (so we lost "polymorphism", too). Even more, the razor helper is tied to the Index.cshtml page:
* It has to be defined within the page where it is used.
* It relies on expression to have the same type arguments as the one the page needs.
Use Partial in editor template insted of #Html.EditorFor(m => m, ...):
#model SpecialChild
#{
ViewData["Extend"] = new MvcHtmlString("<span>SpecialChild is a </span>");
}
#Html.Partial("~/Views/Shared/EditorTemplates/GeneralChild.cshtml", Model)

Razor code comments

I'm trying to re-write very long complex if statements and switch statements inside my razor view . So comments would definetly help the readibility. Problem is this
#if(IsManager(){
switch(Model.ReportType){
case ReportType.NewReport:
if (case1){
// bla bla bla
//
}
else if (case2){
// bla blab bla
//
}
break;
case ReportType.FooReport:
if (fooBar){
....
so any ways, there is very simplified example of something that would be in a razor code block. Now if I want to add simple comments in there to help readibility - it all breaks!! ex.
#if(IsManager(){ #* TALENT MANAGER *#
switch(Model.ReportType){
case ReportType.NewReport:
that makes intellisense get really mad for some reason, I tried this style of comment
#if(IsManager(){ // TALENT MANAGER
switch(Model.ReportType){
case ReportType.NewReport:
no luck , am I doing something wrong??
You can group reusable (or complex) view code into a helper. Helpers are definable in their own file or in a view.
#helper DoSomethingWhenManager(bool isManager, ReportModel model)
{
if(isManager)
{
switch(model.ReportType) // This is a comment about the report
{
// ...
}
{
}
View:
<div>
#DoSomethingWhenManager(IsManager(), Model)
</div>
This one works fine for me
#if (1 < 9) { //Hello
<b>Hey, there!</b>
}
I use Visual Studio 2013 Express for Web

In MVC 4 How do I Add multiple Collections to a session?

I'm using MVC 4 with Razor Syntax to create a collection based on a class that was created using scaffolding (Database first based development) and I can add the first collection to the Session and return it to the Index view and display it on the page.
When I attempt to add a second collection to the Session Variable it gives me a error.
Unable to cast object of type
'System.Collections.Generic.List`1[EagleEye.Models.tblTask]' to type
'EagleEye.Models.tblTask'.
What am I doing wrong - how do I add 2 collections to the session?!
Index.cshtml (My Index view using Razor syntax)
#model List<myApp.Models.tblTask>
<table>
#{
foreach (var tblTask in Model)
{
<tr>
<td>
TaskName: #tblTask.Name
</td>
<td>
Desc: #tblTask.Description
</td>
<td>
Schedule: #tblTask.Freq #tblTask.FreqUnit
</td>
<td>
Reocurring?: #tblTask.ReocurringTask.ToString()
</td>
</tr>
}
}
</table>
Here's the "ActionResult" portion of the code from my HomeController.cs:
[HttpPost]
public ActionResult CreateTask(tblTask newTask)
{
var TaskCollection = new List<tblTask>();
if (Session["TaskCollection"] != null)
{
TaskCollection.Add((tblTask)Session["TaskCollection"]);
}
TaskCollection.Add(newTask);
Session["TaskCollection"] = TaskCollection;
return RedirectToAction("Index");
}
public ActionResult Index()
{
var TaskCollection = new List<tblTask>();
if (Session["TaskCollection"] != null)
{
TaskCollection = (List<tblTask>)Session["TaskCollection"];
}
return View(TaskCollection);
}
When I add the first entry it works fine and shows up on my index view. When I try to add the second collection of tasks, it tells me:
Unable to cast object of type
'System.Collections.Generic.List`1[EagleEye.Models.tblTask]' to type
'EagleEye.Models.tblTask'.
I've been fighting this for a few days now and have been developing for a while, but am just beginning to learn the power of asking questions when I'm stumped (instead of just continuing to beat my head against the wall until something caves in (often my head), so if my question is not well formed, please let me know.
Thanks!
Dan
Because, inside your if condition, you are casting the Session["TaskCollection"](which is a collection of tblTask to a single instance of tblTask.
This should work.
[HttpPost]
public ActionResult CreateTask(tblTask newTask)
{
var TaskCollection = new List<tblTask>();
//Check whether the collection exist in session, If yes read it
// & cast it to the tblTask collection & set it to the TaskCollection variable
if (Session["TaskCollection"] != null)
{
TaskCollection= (List<tblTask>) Session["TaskCollection"];
}
if(newTask!=null)
TaskCollection.Add(newTask);
//Set the updated collection back to the session
Session["TaskCollection"] = TaskCollection;
return RedirectToAction("Index");
}
I finally see the light -- Note the change in the HomeController.cs "TaskCollection = (List)Session["TaskCollection"]; "
[HttpPost]
public ActionResult CreateTask(tblTask newTask)
{
var TaskCollection = new List<tblTask>();
if (Session["TaskCollection"] != null)
{
//Here is the line that changed -- the following line works~
TaskCollection = (List<tblTask>)Session["TaskCollection"];
}
TaskCollection.Add(newTask);
Session["TaskCollection"] = TaskCollection;
return RedirectToAction("Index");
}

NullReferenceException MVC4 C# Most likely beginner fail

I have been following
http://pluralsight.com/training/Courses/TableOfContents/mvc4-building
to learn some MVC C# for my Company, btw completely amazing Video.
I am populating a View with a SQL source.
In Debug I can definitely tell all my connections work, and I get to my foreach loop that should display all the data in that table
On my #Foreach( var item in Model ) it throws the NullRefException on my Model... here's the code I have
this is my complete view
#model IEnumerable<OilNGasWeb.ModelData.Clients>
#{
ViewBag.Title = "CLS-Group";
}
#foreach(var item in Model)
{
<div>
<h4>#item.Client</h4>
<div>#item.Address</div>
<div>#item.City</div>
<div>#item.State</div>
<div>#item.Zip</div>
<div>#item.ContactName</div>
<div>#item.ContactEmail</div>
<div>#item.County</div>
<div>#item.Authorized</div>
<hr />
</div>
}
So I'm thinking it is instantiated here
#model IEnumerable<OilNGasWeb.ModelData.Clients>
but just incase I was wrong maybe it's instantiated in the Home controller in the Index Action?
public ActionResult Index()
{
var Model = _db.Clients.ToList();
return View();
}
Please help me figure out why it's throwing this exception thanks. I wouldn't think you needed more code. but if you do let me know what M , V , C to post for you, as said above the data part works great.
public ActionResult Index()
{
var model = _db.Clients.ToList();
return View(model);
}
You need to pass the model to the view, otherwise it will be null.

Razor renderpartial exception - expected '}"

In my code:
#foreach (var post in Model.Posts)
{
Html.RenderPartial("ShowPostPartial", post);
}
i have an excepion on RenderPartial line.
error CS1513: } expected.
What am I doing wrong?
For completeness, here's another way of causing this:
#if(condition)
{
<input type="hidden" value="#value">
}
The problem is that the unclosed element makes it not obvious enough that the content is an html block (but we aren't always doing xhtml, right?).
In this scenario, you can use:
#if(condition)
{
#:<input type="hidden" value="#value">
}
or
#if(condition)
{
<text><input type="hidden" value="#value"></text>
}
This is basically the same answer that Mark Gravell gave, but I think this one is an easy mistake to make if you have a larger view:
Check the html tags to see where they start and end, and notice razor syntax in between, this is wrong:
#using (Html.BeginForm())
{
<div class="divClass">
#Html.DisplayFor(c => c.SomeProperty)
}
</div>
And this is correct:
#using (Html.BeginForm())
{
<div class="divClass">
#Html.DisplayFor(c => c.SomeProperty)
</div>
}
Again, almost same as the earlier post about unclosed input element, but just beware, I've placed div's wrong plenty of times when changing a view.
MY bad.
I've got an error in the partial view.
I've written 'class' instead of '#class' in htmlAttributes.
I've gotten this issue with Razor. I'm not sure if it's a bug in the parser or what, but the way I've solved it is to break up the:
#using(Html.BeginForm()) {
<h1>Example</h1>
#foreach (var post in Model.Posts)
{
Html.RenderPartial("ShowPostPartial", post);
}
}
into:
#{ Html.BeginForm(); }
<h1>Example</h1>
#foreach (var post in Model.Posts)
{
Html.RenderPartial("ShowPostPartial", post);
}
#{ Html.EndForm(); }
The Razor parser of MVC4 is different from MVC3. Razor v3 is having advanced parser features and on the other hand strict parsing compare to MVC3.
--> Avoid using server blocks in views unless there is variable declaration section.
Don’t : \n
#{if(check){body}}
Recommended :
#if(check){body}
--> Avoid using # when you are already in server scope.
Don’t : #if(#variable)
Recommended : #if(variable)
Don't : #{int a = #Model.Property }
Recommended : #{int a = Model.Property }
Refrence : https://code-examples.net/en/q/c3767f

Categories