Using Handlebars.Net, I'd like to create a HandlebarsHelper that will replace carriage returns and newlines with <br> tags. It should look something like this:
string pattern = #"/(\r\n|\n|\r)/gm";
string replacement = "<br>";
Regex rgx = new Regex(pattern);
Handlebars.RegisterHelper("link_to", (string text) =>
{
text = rgx.Replace(text, replacement);
});
The compiler (or resharper) is telling me that it can't tell if I'm trying to use HandlebarsBlockHelper or HandlebarsHelper, and I'm missing arguments in either case.
What's the difference between the two?
I can't seem to find much documentation for any of this. Is there documentation for the above two mentioned objects as well as HelperOptions, and how to use TextWriter, the dymanic context and the argument object list?
It ended up looking like this with a little help from the C# Regex class:
var newlineRegx = new Regex("(\\r\\n|\\n|\\r)",RegexOptions.Multiline);
Handlebars.RegisterHelper("handleNewLines", (output, context, arguments) =>
{
var str = newlineRegx.Replace((string)arguments[0], "<br>");
output.Write(str);
});
To answer my questions:
HandleBarsBlockHelper provides a mechanism for invoking a helper with a block of the template. Block helpers can then invoke that block zero or more times with any context it chooses. Check out the description for Helpers for more info (at the bottom you'll see a button labeled "Learn More: Block Helpers").
TextWriter.Write is how you output your transformed text.
context will essentially be the JSON object you passed into the delegate you created with Handlebars.Compile().
The argument object lists contains the arguments that appear along side the helper you're defining, which you'll use in your HTML template
To better understand the argument object list, it'll help to see how I used this helper in my HTML template:
<div>
<p>{{{handleNewLines StringVariable}}}</p>
</div>
Where "StringVariable" is a member of the JSON object I passed into the delegate I created with Handlebars.Compile()
Related
Under ASP.NET MVC are you supposed to pick up QueryString params the same way you do in ASP.NET WebForms? or does the [AcceptVerbs(HttpVerbs.Get)] declaration get used somehow?
Query string parameters can be accepted simply by using an argument on the action - i.e.
public ActionResult Foo(string someValue, int someOtherValue) {...}
which will accept a query like .../someroute?someValue=abc&someOtherValue=123
Other than that, you can look at the request directly for more control.
I think what you are looking for is
Request.QueryString["QueryStringName"]
and you can access it on views by adding #
now look at my example,,, I generated a Url with QueryString
var listURL = '#Url.RouteUrl(new { controller = "Sector", action = "List" , name = Request.QueryString["name"]})';
the listURL value is /Sector/List?name=value'
and when queryString is empty
listURL value is /Sector/List
You can always use Request.QueryString collection like Web forms, but you can also make MVC handle them and pass them as parameters. This is the suggested way as it's easier and it will validate input data type automatically.
I recommend using the ValueProvider property of the controller, much in the way that UpdateModel/TryUpdateModel do to extract the route, query, and form parameters required. This will keep your method signatures from potentially growing very large and being subject to frequent change. It also makes it a little easier to test since you can supply a ValueProvider to the controller during unit tests.
Actually you can capture Query strings in MVC in two ways.....
public ActionResult CrazyMVC(string knownQuerystring)
{
// This is the known query string captured by the Controller Action Method parameter above
string myKnownQuerystring = knownQuerystring;
// This is what I call the mysterious "unknown" query string
// It is not known because the Controller isn't capturing it
string myUnknownQuerystring = Request.QueryString["unknownQuerystring"];
return Content(myKnownQuerystring + " - " + myUnknownQuerystring);
}
This would capture both query strings...for example:
/CrazyMVC?knownQuerystring=123&unknownQuerystring=456
Output: 123 - 456
Don't ask me why they designed it that way. Would make more sense if they threw out the whole Controller action system for individual query strings and just returned a captured dynamic list of all strings/encoded file objects for the URL by url-form-encoding so you can easily access them all in one call. Maybe someone here can demonstrate that if its possible?
Makes no sense to me how Controllers capture query strings, but it does mean you have more flexibility to capture query strings than they teach you out of the box. So pick your poison....both work fine.
This is the correct way in .NET 6 (and other netcore)
var Param = Request.Query["IndexString"];
If need to be string
string Param = Request.Query["IndexString"].ToString();
#Context.Request.Query["yourId"]
Under ASP.NET MVC are you supposed to pick up QueryString params the same way you do in ASP.NET WebForms? or does the [AcceptVerbs(HttpVerbs.Get)] declaration get used somehow?
Query string parameters can be accepted simply by using an argument on the action - i.e.
public ActionResult Foo(string someValue, int someOtherValue) {...}
which will accept a query like .../someroute?someValue=abc&someOtherValue=123
Other than that, you can look at the request directly for more control.
I think what you are looking for is
Request.QueryString["QueryStringName"]
and you can access it on views by adding #
now look at my example,,, I generated a Url with QueryString
var listURL = '#Url.RouteUrl(new { controller = "Sector", action = "List" , name = Request.QueryString["name"]})';
the listURL value is /Sector/List?name=value'
and when queryString is empty
listURL value is /Sector/List
You can always use Request.QueryString collection like Web forms, but you can also make MVC handle them and pass them as parameters. This is the suggested way as it's easier and it will validate input data type automatically.
I recommend using the ValueProvider property of the controller, much in the way that UpdateModel/TryUpdateModel do to extract the route, query, and form parameters required. This will keep your method signatures from potentially growing very large and being subject to frequent change. It also makes it a little easier to test since you can supply a ValueProvider to the controller during unit tests.
Actually you can capture Query strings in MVC in two ways.....
public ActionResult CrazyMVC(string knownQuerystring)
{
// This is the known query string captured by the Controller Action Method parameter above
string myKnownQuerystring = knownQuerystring;
// This is what I call the mysterious "unknown" query string
// It is not known because the Controller isn't capturing it
string myUnknownQuerystring = Request.QueryString["unknownQuerystring"];
return Content(myKnownQuerystring + " - " + myUnknownQuerystring);
}
This would capture both query strings...for example:
/CrazyMVC?knownQuerystring=123&unknownQuerystring=456
Output: 123 - 456
Don't ask me why they designed it that way. Would make more sense if they threw out the whole Controller action system for individual query strings and just returned a captured dynamic list of all strings/encoded file objects for the URL by url-form-encoding so you can easily access them all in one call. Maybe someone here can demonstrate that if its possible?
Makes no sense to me how Controllers capture query strings, but it does mean you have more flexibility to capture query strings than they teach you out of the box. So pick your poison....both work fine.
This is the correct way in .NET 6 (and other netcore)
var Param = Request.Query["IndexString"];
If need to be string
string Param = Request.Query["IndexString"].ToString();
#Context.Request.Query["yourId"]
I'm learning ASP.NET MVC, and I have some problems, I would like to know what's the advantage of using Html.ActionLink() method instead of a normal Anchor tag, I don't see any obvious advantage yet, mostlyu because I have more problems using ASP's built-in method. Something else I would like to know, is how to add various attributes to Html.ActionLink(), I'm using this:
#Html.ActionLink("About", "About", "Home", new{ area="" }, new Dictionary<string, Object>{ { "class", "about-link" }, { "aria-role", "button" }, { "title", "About us..." } })
I found this in StackOverflow, but it just doesn't work, and I've been trying many things, but nothing.
This is the method signature of most likely interest to you:
public static MvcHtmlString ActionLink(
this HtmlHelper htmlHelper,
string linkText,
string actionName,
string controllerName,
object routeValues,
object htmlAttributes
)
For your instance, that would result in the following code:
#Html.ActionLink("About", "About", "Home", new { area = "" }, new { #class = "about-link", aria_role = "button", title = "About us..." })
A few things to note:
The first anonymous object is for route values, and the second anonymous object is for HTML attributes to apply to the anchor tag.
Since class is reserved keyword, you must prefix it with # inside anonymous objects. It will still be output as class on the anchor tag.
Similarly, aria-role is invalid C# syntax, so you have to use an underscore instead of a dash: aria_role. The built-in HtmlHelper extensions that accept htmlAttributes process the _ and turn it into a - when rendering the HTML.
Now, in terms of why you want to use this in the first place, #Christos points out correctly that by letting MVC construct the URL, your links continue to work even if your routing changes, while if you hardcoded the URL, it would fail. However, he misses the point that this doesn't require using Html.ActionLink. You can just as easily do something like the following:
<a href="#Url.Action("About", "Home", new { area = "" })" class="about-link" aria-role="button" title="About us...">
About
</a>
This is especially handy when you need something inside the link other than just straight text, like an icon, perhaps. If you find it easier to work directly with the HTML attributes, then you can do that. There's nothing wrong with this and you don't have to use Html.ActionLink. However, do still use Url.Action or one of its siblings, so that your URLs are constructed dynamically based on your route configuration.
The basic advantage of using #Html.ActionLink for creating a link instead of using an anchor element is the fact that the output is derived from the routing configuration. That means if you change something in the routes, automatically this change would be reflected to the links you have created using this helper.
Here you will find a detailed list with all the signatures of this method.
I'm reading this excellent article regarding razor template delegate. http://www.prideparrot.com/blog/archive/2012/9/simplifying_html_generation_using_razor_templates
While I understand how it's used, as in
Func<dynamic, HelperResult> variable = #<var>#item.ProductName</var>
My question is, how exactly razor engine translated "#<var>#item.ProductName</var>" into a delegate in the background? As in
Func<dynamic, HelperResult> variable = delegate(dynamic x)
{
(what goes on in here?)
}
is #item a reserved keyword that razor parses out? Can it be used in any other convention? say #column or #row or any other ways?
Thanks a lot. Like I said, i'm more interested in how razor view engine translated the template statements into actual code in the background.
[Edit]. Thanks to Brad for pointing out Andrew's article. so above statement "#<var>#item</var>" will translate into
Func<dynamic, HelperResult> variable = delegate(dynamic item)
{
return new Microsoft.WebPages.Helpers.HelperResult(__writer => {
#__writer.Write(" ");
#__writer.Write("<var>");
#__writer.Write(item.ProductName); <--- what's happening here?
#__writer.Write("</var>");
}
So I see razor automatically parses out #<var> and </var> into separate strings and such, my question in regards to "item.ProductName" is..suppose "item" is a "Proudct" type, then is the following what razor is trying to do?
First, razor parses "#item.ProductName" separated by comma ".", get "item" and "ProductName".
Then because of the "dynamic" parameter, in the background, .NET will attempt to find the value of the property "ProductName" of the item "Product"?
Thanks
Never mind. I don't know why i didn't make the connection.
I asked another question in regards to DynamicObject DynamicObject? How does the following code work? and #Alxandr explained this regarding "dynamic". So essentially, it becomes
dynamic item = new Product(...);
String ProductName = item.ProductName;
So in essence, "dynamic" parameter in the background use CSharpGetMemberBinder and through reflection, figure out the "ProductName" of the object "Product".
razor template has a pretty brilliant design
I have a razor helper method that needs to take in a Func<> that will return some HTML content to print out. This is what I originally had:
#helper node(string title, Func<HelperResult> descriptions)
{
....
<div>#descriptions()</div>
....
}
#node("title",
new Func<HelperResult>(() =>
{
return new HelperResult(
#<text>
<span>"desc1"</span>
<span>"desc2"</span>
</text>);
}))
Unfortunately with this my text never gets printed out. No error either.
So I learned about inline helpers, and changed the calling method to this:
#node("title",
#<text>
<span>"desc1"</span>
<span>"desc2"</span>
</text>)
However now I get a compilation error saying
"Delegate 'System.Func' does not
take 1 arguments".
But I'm not passing in any arguments.
So if I change it to Func<object,HelperResult> and then call it using #descriptions(null) I get the following error:
"Cannot use a lambda expression as an argument to a dynamically
dispatched operation without first casting it to a delegate or
expression tree type"
I'm sure I have something wrong somewhere, but I'm not sure what it is.
Edit: I think I may have solved that problem but it introduces some other issues.
What I did was to cast the lambda before passing into a dynamic method. I guess that's what the error was trying to say:
#node("title",
((Func<dynamic, HelperResult>)(#<text>
<span>"desc1"</span>
<span>"desc2"</span>
</text>))
That works and it prints out the span tags correctly. Unfortunately I have to pass in a useless parameter when calling this Func.
Now the issue I have is that my real function does a bit more than just write some spans. It's more like this:
#node("title",
((Func<dynamic, HelperResult>)(#<text>
<span>#Helpers.Format(resource.Description,"item")</span>
</text>))
Where #Helpers.Format is another helper and resource is a (dynamic) variable from the page model.
Of course now the code runs but nothing is printed out (inside the <span> tag). I put a breakpoint inside my Format helper function, and it hits it and all the parameters are correctly set, so I'm not sure why it wouldn't output correctly. Similarly if I just change it to
resource.Description
then nothing still gets output.
Since it works well outside of this context, I wonder does Razor's inline helpers not capture the outer variables?
Actually HelperResult is something Microsoft would rather you didn't use, as evidenced by documentation:
public class HelperResult : IHtmlString in namespace
System.Web.WebPages
Summary: This type/member supports the .NET Framework infrastructure
and is not intended to be used directly from your code.
A possible solution to your problem might be to wrap your description function in another helper and then pass that helper as a method group to your node helper, like this:
#helper Node(string title, Func<HelperResult> descriptions)
{
<div>#descriptions()</div>
}
#helper Description() {
<span>desc1</span>
<span>desc2</span>
}
#Node("title", Description)
In any case, your first idea shouldn't work because a parameter of type Func is in fact equal to a parameterless function, in which case you need to write the lambda expression like this:
myFunction( () => doSomething)
So your function call would have been:
#node("title", () =>
#<text>
<span>"desc1"</span>
<span>"desc2"</span>
</text>)
Since the future of these helpers is a bit dubious though, I would consider switching to either HtmlHelpers for small snippets of html or Partials for larger chunks.
#Test(new Func<object, HelperResult>[]{#<text>hello</text>})
#Test(new Func<object, HelperResult>[]{#<text>hello</text>,#<text>world</text>})
#helper Test(params Func<object, HelperResult>[] results)
{
foreach (var result in results)
{
#result(null);
}
}