Razor - how to render content into a variable
How to render a piece of Html into a variable in Razor? In Spark I used to write the following code:
<content var="t">
<a class="tab" href="">Tab name</a>
</content>
<content var="tc">
<div class="tabcontent">
<p>Here goes tab content</p>
</div>
</content>
!{tabs(t, tc)}
two variables get passed to a macro that does all the nice wrapping of the content into the tab sheet.
What's the best way to do the same in Razor?
Update: I think I got it..
In Razor, the @<text>...</text>
construct can be user to produce lambda expressions, which can be reused later, which is an extended equivalent of assigning a piece of HTML to a variable. The above example 开发者_JS百科can be implemented in the following way:
Func<int, object> t =
@<text>
<a class="tab" href="">Tab name</a>
</text>;
Func<int, object> tc =
@<text>
<div class="tabcontent">
<p>Here goes tab content</p>
</div>
</text>;
@tabs(t(0), tc(0))
I just can't figure out how to write parameterless lambdas (Func<object>
). the int
parameter in both lambdas above is a dummy. Razor seems to require one parameter (and already creates a variable "item" to denote it within the expression).
Basically the OP already answered the problem in that you could do something like:
@{
Func<dynamic, object> a = @<text>
Some Text
</text>;
@a(new object())
}
If the text is for a single line only you could even use the "@:" operator, just remmebr to have a semicolon (or if it needs any closing brackets or parenthesis) on the next line, as in the following example:
@{
Func<dynamic, object> a = @: Some Text
;
@a(new object())
}
However you can capture it directly as a string if you want
@{
string a = ((Func<dynamic, object>)(@<text>
Some Text
</text>))("").ToString();
@a //Output directly as a string
}
You could even encapsulate it in a function:
@functions{
public string ToString(Func<dynamic, object> input)
{
return input("").ToString();
}
}
@{
string a = ToString(@<text>
Some Text
</text>);
@a //Output directly as a string
}
Just in case anyone else finds this post (as I did), Andy's Update is almost there. In addition to the example given, all you have to do to access the 'int' in the example given is reference @item
. In @<text></text>
blocks, the variable item
contains the model it was called on.
Here's an example of how it can be used:
@model PageData
@{
Func<Customer, object> sayHi =
@<text>
<li>Hello @(item.FirstName)!</li>
</text>;
}
<ul>
@foreach(var customer in Model.Customers)
{
sayHi(customer);
}
</ul>
In most instances you should probably use a partial view instead of a function like this. But in the rare instances that a partial view is not possible (such as when using the RazorEngine library), this works.
Perhaps you can use HtmlString? I don't think I like this much, but here's what I'd try as an exact translation of what you have...
@{
var t = new HtmlString("<a class='tab' href=''>Tab name</a>");
var tc = new HtmlString("<div class='tabcontent'><p>Here goes tab content</p></div>");
}
@tabs(t, tc)
So... I don't know what your Spark macro looks like, but it seems like an opportunity to use a helper in Razor. You might have something like:
@helper Tabs(string tabName, string tabContent)
{
<!-- some wrapper code -->
<a class="tab" href="">@(tabName)</a>
<!-- some more wrapper code -->
<div class="tabcontent">
<p>@(tabContent)</p>
</div>
<!-- still more wrapper code -->
}
Then you call that from in your page like so:
@Tabs("Tab Name", "Here goes tab content")
If you have an IHtmlContentBuilder in your Razor view, you can use these extensions.
public static IHtmlContentBuilder AppendRazor(this IHtmlContentBuilder htmlContentBuilder, Func<IHtmlContent, dynamic> lamda)
{
var html = lamda(null);
return htmlContentBuilder.AppendHtml(html);
}
public static IHtmlContentBuilder AppendRazor<T>(this IHtmlContentBuilder htmlContentBuilder, Func<T, IHtmlContent> lamda, T model)
{
var html = lamda(model);
return htmlContentBuilder.AppendHtml(html);
}
Usage
@{
HtmlContentBuilder contentBuilder = new HtmlContentBuilder();
contentBuilder.AppendRazor(@<text><p>Hello @Model.Name<p></text>);
contentBuilder.AppendRazor(@<text><p>Hello @item.CustomerName<p></text>, customer);
}
<div>
@contentBuilder
</div>
精彩评论