Are lambda expressions supported by Razor? - asp.net-mvc

Are lambda expressions/anonymous methods supported in the Razor view engine?
I am having difficulty expressing the following in Razor:
#Model.ToList().ForEach(i =>
{
if (i.DealerName != null)
{
<text>
#i.DealerName
</text>
}
}
Note: I know can solve this with #foreach but I need a similar solution for a 3rd party MVC control. It using this mechanism for setting the content of the control. It works fine for MVC .ASPX views but cannot get it to work with Razor.
MVC .ASPX equivalent (the code I would like to convert to Razor syntax):
<% Model.ToList().ForEach(i =>
{
if (i.DealerName != null)
{
%> <%=i.DealerName%> <%
};
});
%>
This is for the Razor engine that ships with ASP.NET MVC3.

Instead of your <text>#i.DealerName</text> block you could use a Response.Write(i.DealerName);
The result is the same, as if you drop this in a Razor page - it will execute while rendering page.. And frankly - I'm pretty sure this is what it will be compiled into anyway.
Also, since ForEach() returns void, you'd have to drop it in the page as a code block.
So your code would look something like this:
#{
Model.ToList().ForEach(i =>
{
if (i.DealerName != null)
{
Response.Write(i.DealerName);
}
});
}
UPD: If you have more serious formatting, you can resort to this nice little trick:
(unfortunately the code colouring here will not give this snippet any credit, but you'll definitely see what I mean if you drop this in visual studio. Note: this will only work in Razor pages, not code files :) )
#{
Model.ToList().ForEach(i =>
{
if (i.DealerName != null)
{
Response.Write(((Func<dynamic, object>)(
#<text>
<b>Hello Dealer named: #item.DealerName
Multiline support is <em>Beautiful!</em>
</text>)).Invoke(i));
}
});
}
Hope that makes sense :)

Alternatively, you can create a lambda function, and call that for each item in the body of your Razor code (the idea came from Andy in this post):
#model IEnumerable<Dealer>
#{
Func<Dealer, object> sayHi =
#<text>
<b>Hello Dealer named: #(item.DealerName)</b>
Multiline support is <em>Beautiful!</em>
</text>;
}
<div>
#foreach(var dealer in Model.ToList())
{
sayHi(dealer);
}
</div>

Yes, they are supported. BUT, Razor has some weird escaping rules and extra braces will cause it to choke sometimes, including those in extended lambda expressions.
You can simplify the #Artioms answer a bit to remove those extra braces with a where and optionally a select clause
#{
Model.ToList().ForEach(i =>
{
if (i.DealerName != null)
{
Response.Write(i.DealerName);
}
});
}
becomes
#{
Model.Where(i=>i.DealerName != null).ToList().ForEach(i =>
{
Response.Write(i.DealerName);
});
}
Could also become
#{Model.Where(i=>i.DealerName != null).Select(i=>i.DealerName)
.ToList().ForEach(Response.Write);}
Yay functional styles!

Related

How to use ViewBag in Kendo Grid ClientTemplate's If condition

I am loading some ids to a ViewBag to use it's data in the related View.
var userAccountList =serviceResponse.RoleList.Select(x => x.RoleId).ToList();
ViewBag.UserRoles = userAccountList;
this result is a List<string>.
In the View a Kendo Grid retrieves data from json.
#(Html.Kendo().Grid<RoleModel>().Name("KendoGrid").Scrollable().Columns(columns =>
{
columns.Bound(x => x.Id)
.HtmlAttributes(new { style = "text-align:center;"})
.ClientTemplate("# if ( Id != '3'){
#<a class='k-button' href=\"/Role/Delete/#= Id #\"><span class='k-icon k-delete' style='pointer-events: none;'></span>Delete</a># }#")
.Width(85).Sortable(false)
.Hidden(!((BaseController)this.ViewContext.Controller).UserHasPermission(PermissionType.RoleDelete));
columns.Bound(x => x.Name);
....
}
When I use static values such as '3' I could prevent to show a tag that was used as delete button. How can I use ViewBag.UserRoles in this conditional if the list contains Id that's bound to column?
Generally in order to use Razor you would have to do something like that
.ClientTemplate("# if ( Id != "'+ #ViewBag.UserRole +'")
If we were talking about one string value.
Now for your case you could use Template instead of ClientTemplate with something like this
.Template(
#<text>
#if (ViewBag.UserRoles.Any(u => u == item.Id))
{
... add your link
}
</text>
A couple more examples you can find in this post.
Most probably it has documentation too by I couldn't find what I was looking for at the moment.

Knockout MVC with existing C# code - looping

The code in my view -
#{ int tabIndex = 0; }
#using (var metricGroup = ko.Foreach(m => m.MetricGroups))
{
tabIndex++;
<div id="tabs-#tabIndex" > ... </div>
}
The issue here is for all the divs rendered, the id is always the same - "tabs-1"
instead of that, it should be "tabs-1", "tabs-2", "tabs-3" ...
Can anyone please help me out with this issue?
I have a highly complex view and Knockout MVC is driving me crazy
Because of the ko.Foreach your HTML will be generated on the client side, so setting the your div's id with Razor does not work because the Razor code is executed on server side.
What you need to do is to generate the id's on the client side with Knockout using the $index() binding context property, and the attr binding:
#using (var metricGroup = ko.Foreach(m => m.MetricGroups))
{
<div data-bind="attr: { id: 'tabs-' + $index() }" > ... </div>
}
The Knockout-Mvc's ko.Bind.Attr method is not working with the GetIndex() method so you need to write out the this Knockout binding expression by hand.

Need to upgrade a simple page post back form to use some row "inpage" postback mechanism?

I am using MVC3, Razor and C#.
I have implemented a simple and robust inline editing solution for a grid.
Basically I use Razor to build my form which encloses the grid, and then the row that matches the item id gets opened up as the editable row which is coded as a partial View.
The Grid View (part):
#using (Html.BeginForm("Edit", "GridTest"))
{
<table>
<tr>
<th>col1</th>
<th>Col2</th>
</tr>
#{
foreach (var item in Model)
{
<tr>
#{
if ((Model.ItemId == item.Id))
{
Html.RenderPartial("_EditRow", item);
}
else
{
Html.RenderPartial("_DisplayRow", item);
}
}
</tr>
}
</table
}
EditRow.cshtml
#Html.TextBoxFor(p=>p.Name)
Save
Cancel
#Html.HiddenFor(p=>p.Id)
DisplayRow.cshtml
<td>
#Model.Name
</td>
<td>
#Html.ActionLink("Edit", "Edit", "GridTest", new {id = Model.Id}, null)
</td>
GridTest/Edit Action
public ActionResult Edit(int id)
{
var myRecord = db.Orders.First(p => p.Id == id);
return View("Index",myRecord);
}
GridTest/Edit Post Action
[HttpPost]
public ActionResult Edit(Order myRecord, string btn="")
{
if (btn == "Save")
{
if (ModelState.IsValid)
{
Order myCurrentRecord = db.Order.First(p => p.Id == myRecord.Id);
myCurrentRecord.Name = myRecord.Name;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(myRecord);
}
else
{
return RedirectToAction("Index");
}
The above code shows the design. It works greats and is simple. However it causes a postback of the complete page, and I would like to stop this "flashiness". So I suspect I need to somehow tweak the above code such that the "EditRow" posts inline, without refreshing the entire page. I suspect I am looking at using Ajax?
So how can the above code be simply upgraded to prevent complete page refresh, but rather row refresh?
Many thanks in advance.
At its simplest, you can probably just capture the submit event of the form and serialize that form to an AJAX POST. Something like this:
$('form').submit(function () {
$.post('#Url.Action("Edit", "GridTest")', $('form').serialize())
.done(function(data) {
// AJAX call is complete
// do something on the page?
});
return false;
});
This will use the same controller action in the same way that the form does, just via AJAX. The controller action will also respond the same way, which probably isn't what you want with an AJAX request. You might instead want to return some JSON data to indicate success, error conditions, results of server-side processing, etc. Something as simple as this can just indicate success from the controller action:
return Json(true);
You can, of course, return any structured data by passing it to Json(), which will serialize it to JSON data as the data value in the JavaScript done handler.
Edit: If you want to replace a piece of the client-side content wholesale with a partial view, you can still return that partial view in the AJAX request. The controller action can do something like this:
return PartialView("_DisplayRow", myRecord);
(Assuming myRecord is the type that is bound to that partial view.)
Then you'd have something for the done handler in the client-side code. Maybe something like this:
$('tr.someClass').html(data);
The idea here is that the tr element which is the "edit row" should be uniquely identified in some way (I'm using a class in my selector at the moment, but you can use whatever works for you), and its contents should be replaced with the contents of the partial view being returned from the server-side code.

Looking for alternate ways to create blocks of HTML code in ASP.NET MVC 3

I'm not sure how to phrase my question, so I essentially want to be able to do something like this, in ASP.NET MVC 3:
#myJsHtmlCustomCode
{
<div><h1>Title</h1></div>
}
where anything in that myJsHtmlCustomCode block would be surrounded with some custom JavaScript/HTML code that I wrote.
I know I could use something like myJsHtmlCustomCode.Begin() and myJsHtmlCustomCode.End() in my code, but that doesn't provide the same formatting structure.
If anyone knows of a similar way to achieve the same objective, and get the automatic outlining/indent formatting, that would be great.
Just for reference, I wanted the the #myJsHtmlCustomCode to surround the code with for instance, another <div id="myTestId" onclick="thisClickEvent"></div> for the resulting code to look like...
<div id="myTestId" onclick="thisClickEvent">
<div><h1>Title</h1></div>
</div>
Option 1
You can wrap your code in an object that implements IDisposable, just like you use #using (Html.BeginForm())
Your code could be like this:
public class MyJsHtmlCustomCode : IDisposable {
private ViewContext _ctx;
public MyJsHtmlCustomCode (HtmlHelper html, /* other params */) {
_ctx = html.ViewContext;
/* Write begin tags */
_ctx.Writer.Write("html => opening tags"); }
public Dispose() {
_ctx.Writer.Write("html => closing tags");
}
}
and the extension:
public static MyJsHtmlCustomCode BeginMyJsHtmlCustomCode(this HtmlHelper html /* other params */) {
var result = new MyJsHtmlCustomCode(html);
return result;
}
Usage:
#using(Html.BeginMyMyJsHtmlCustomCode()) {
<div>This is surrounded by your code </div>
}
Option 2
You can use Razor Templated Delegates:
#{
Func<dynamic, object> b = #<strong>#item</strong>;
}
<span>This sentence is #b("In Bold").</span>
<div>#b(
#<span>
#DateTime.Now
</span><span>Example of more complex logic
</span>
)</div>
While I must admit I do not completely understand your question, whenever I need to do programatic custom HTML manipulation in .Net MVC 3 I use the Html Agility Pack.
Could you achieve your desired result using #section ?
e.g.: in one cshtml, possibly the _Layout:
<script type="text/javascript">
// whatever you want
// more whatever you want
#RenderSection("jsCode", false)
// even more whatever you want
</script>
Then in your actual view cshtml:
#section jsCode{
<div><h1>Title</h1></div>
}
You could possibly use a partial view for the js bit e.g.

Conditional ASP.NET MVC razor sections

I want to define this section only if some property (Model.ReadOnly) is false.
#section toolbar {
<div class="tool">
<div class="row">
#Html.ActionLink( Resources.Strings.Edit, "Edit", "Profile" )
</div>
<div class="row">
#Html.ActionLink( Resources.Strings.Delete, "Delete", "Profile" )
</div>
</div >
}
I tried wrapping it up in #if ( !Model.ReadOnly ) {} but it doesn't work.
Is there a way to do this?
I do not want to define an empty section (as #itsmatt suggests), the layout of my page changes whether the section is defined or not (using IsSectionDefined( "toolbar" )).
This should work.
#if (!Model.ReadOnly)
{
<text>
#section toolbar {
}
</text>
}
I never said it would be pretty ;-)
This works for me:
#section SomeSection {
#if (!Model.ReadOnly)
{
}
}
Essentially flipping where the conditional is. This essentially results in an empty section if Model.ReadOnly is true.
Update:
So, what about moving that section to a PartialView and doing something like:
#Html.Partial("MyAction")
in your View and then let the MyAction return you the appropriate PartialView based on the ReadOnly value? Something like:
public PartialViewResult MyAction()
{
...
// determine readonly status - could have passed this to the action I suppose
if (ReadOnly)
{
return PartialView("TheOneThatDefinesTheSection");
}
else
{
return PartialView("TheOneThatDoesNotDefineTheSection");
}
}
Seems like that would work just fine.
Bertrand,
See:
Razor If/Else conditional operator syntax
basically (para-phrasing), ... Razor currently supports a subset of C# expressions without using #() and unfortunately, ternary operators are not part of that set.
also, this may be a way around the issue:
conditional logic in mvc view vs htmlhelper vs action
basically, use the if logic to call a partialview to satisfy your criteria.
[edit] this was my basic thinking (where your #section code is defined in that partial):
#if(!Model.ReadOnly)
{
#Html.Partial("toolbar")
}

Resources