There are a lot of questions, here and everywhere, regarding the impossibility of using HtmlHelper extension methods (like ActionLink) in an #helper (razor) method.
Right now, in my project, I solved the problem passing as an extra parameter the current page (System.Web.Mvc.WebViewPage page) to the #helper, like in
#helper HelperFunction(SampleParameter sp, System.Web.Mvc.WebViewPage page)
and using it (trivially) as in
{
...
#page.Html.ActionLink("Title", "Action")
...
}
I would like to know if it's too stupid :-), and why. It would be better, of course, to have direct access to the current HtmlHelper of the page where the #helper is called, but, anyway... if this a good solution...
Andrea
I was curious why this didn't work, so I had a little look.
When you put code into the App_Code folder, it inherits from System.Web.WebPages.HelperPage and although this has a Html property, it's a System.Web.WebPages.HtmlHelper and not a System.Web.Mc.HtmlHelper, which is why you can't find things like ActionLink on it :(
I had a quick look around, and found this answer from Andrew Nurse:
Omar's got the right answer here, but
I wanted to add something (do feel
free to mark Omar's response as the
answer).
We were aware of this in v1 and
weren't able to get a great fix in the
product, but David Ebbo (an architect
on the ASP.Net team) posted a sample
of a Visual Studio Code Generator that
is basically a first exploration of
the kind of ideas we're looking at to
make this work properly:
http://blogs.msdn.com/b/davidebb/archive/2010/10/27/turn-your-razor-helpers-into-reusable-libraries.aspx
Try that out and see what you think!
Let David know if you have comments by
posting on his blog.
Unfortunately, it looks like you can't even put the Helper outside of App_Code into your Layout class or _ViewStart :(
Related
I've inherited some code... and am trying to convert it to use MVC 3, with Razor, the VBHTML is as follows:
For Each Message As MessageDetailsModel In Model.Messages
#<div id='#Message.HeaderId' class='#Message.HeaderCss' onclick=#(String.Format("shMsgTree('{0}','{1}',{2},'{3}');", Message.HeaderCss, Message.HeaderId, Message.MessageId, Message.UserId))>
... more stuff...
</div>
Next
Stepping through the code, the String.format resolves to this:
shMsgTree('sh_msg_GridItem sh_msg_MessageRead ','divHeader0',40,'{85A433F0-4054-42E7-B778-3EF005E411D3}');
which is what I want on the page, but for some reason, it gets output on the page as this:
shMsgTree('sh_msg_GridAltItem" sh_msg_MessageRead="
The properties on the model are all strings.
Am at a bit of a loss as to how to get it to render. Originally the entire onclick javascript was being returned in the Model, but that didn't render any better either.
Any suggestions would really be welcome. Thanks!
Given our conversation in the comments and the fact that the original Razor is quite hard to read, I think I'd recommend either:
writing a Razor Helper for this small block of code http://weblogs.asp.net/scottgu/archive/2011/05/12/asp-net-mvc-3-and-the-helper-syntax-within-razor.aspx
or writing a normal Extension Method to output the code - http://weblogs.asp.net/jgalloway/archive/2011/03/23/comparing-mvc-3-helpers-using-extension-methods-and-declarative-razor-helper.aspx (this is what I would choose!)
Without stepping through it in code, it's too hard to read the syntax as currently written - so break it out into a separate compact, testable, readable component.
Hope that helps
Stuart
Not sure if this will do it, but your onClickcode needs to be wrapped in quotes, before and after: onClick="#(String.Format(...))"
Let's say I have 2 MVC web projects (web1 and web2) and 1 project containing shared views (common) (using the razorgenerator of David Ebbo)
web1 and web2 both have a test.cshtml file. Several blocks of code in both test.cshtml files are exactly the same.
I'm trying to find out if it's possible to share a declarative helper (#helper) between several cshtml files which are in DIFFERENT projects. So putting a cshtml file in my App_Code does not help (I would need to have 1 in each web project, which is obviously not what I want).
I know I could create a bunch of shared partial views in my 'common' project, but it seems kinda overhead to create 20 cshtml files that each contains a very small portion of html.
I know I can create a standard helper method (static string GenerateAPieceOfHtml(this HtmlHelper helper, ....)), but there I loose the ease of writing html as you can do it in a cshtml file.
For a short while I thought I bumped into an answer that would allow me to do it. But as I wrote in a comment, that code did not compile for me.
I hope my question is clear :)
[Update]
As csharpsi asks in a comment.. I did try out the code from the other post, but it did not spit out any HTML for me. Since I started to think that that answer should probably do the trick since it has 13 upvotes, I decided to give it a second try..
Again I didn't get any output, but then I tried it a little bit different.. and success!
I was trying this (which doesn't spit out any html on the page):
#{ new Test().DoSomething(Model); }
This is the version that DOES WORK:
#{
var html = new Test().DoSomething(Model);
#html
}
Other version that works:
#(new Test().DoSomething(Model))
What should I do with this question? Delete it? Write an answer myself?
Why are you trying to use razor helper for this anyway ? Razor helpers are one-particular-viewengine hack, your application shouldnt rely on them on many places (even amongst different websites). In this case, be sure to use standard MVC way - HTML helper. These you can easily share between websites, for example you can make your own class library full of them.
I'm wondering does the latest release of MvcContrib work with the Razor view engine? I referenced the MvcContrib assembly and the FluentHtml assembly, then I added the required namespace to the ~/View/Web.config as suggested here by Darin. But still, no matter how much I try use the FluentHtml extensions in my views, it doesn't work. (nothing shows up in intellisense when I start with a dot after the html helper)
Am I missing anything?
P.S: this is the first time I use MvcContrib.
I wrote a short blog that post covers using FluentHtml with Razor.
Regarding intellisense, you will only get intellisense for FluentHtml methods on "#this." (not "#Html.") and it only list the strong-typed helpers on views that implement IViewModelContainer<T> (such as ModelWebViewPage<T>). Another possible issue is Resharper. There is a workaround for that.
I´m using mvccontrib and following darin answer it has to work. The steps I followed were:
copy-pasted in bin folder mvccontrib.dll and mvccontrib.fluent.dll
make a reference in references to those dll creating a reference for mvccontrib and mvccontrib.fluent.
two namespaces with the following names:
add namespace="MvcContrib"
add namespace="MvcContrib.FluentHtml"
in my controller I include using MvcContrib.Pagination;
finally I used in my view:
#using MvcContrib.UI.Pager
#using MvcContrib.Pagination
and rebuild.
hope it helps..
Hi I'm working with a project (asp.net mvc) where I need to show pictures on one site. They gone have jquery and be surrounded by a div like <div><img/></div>
I'm relatively new on MVC so I'm not sure what ways are the best to work in it yet. Should I do a ImageHelper so i can access it like <% Html.ImageJquery() %> or should i just do it plain in the view
what are your thoughts on this?
I am not sure if there is any single best practice for this case. As you already said you could create an extension method on a HtmlHelper or just put the code in the view.
Because the "added" code is a very simple (just two divs) I would skip extension method and just add the divs in the view. But if the code is actually more complex I would create a helper.
Cheers!
It depends how often you would use the helper. If it is used in a couple of places it would make sense, because it helps you to reduce redundant code.
The other option you have are partials.
I would go with an Extension method on the HTMLHelper , so that it accepts the 'src' value as a parameter and constructs the image tag accordingly.
Regarding Rendering of UI elements , i did read a blog post on 'Conditional Rendering' which i thought you would find it interesting .
please check the link below .
Conditional Rendering
Thanks ,
Vijay.
I have heard that it's best not to actually have any html in your helpers; my question is, Why not? And furthermore, if you were trying to generate an html list or something like that, how can I avoid actual tags?
Thanks!
-fREW
My advice - if it's small pieces of HTML (a couple of tags) don't worry about it. More than that - think about partials (as pulling strings of html together in a helper is a pain that's what the views are good at).
I regularly include HTML in my helpers (either directly or through calls to Rails methods like link_to). My world has not come crashing down around me. In fact I'd to so far as to say my code is very clean, maintainable and understandable because of it.
Only last night I wrote a link_to_user helper to spits out html with normal link to the user along with the user's icon next to it. I could have done it in a partial, but I think link_to_user is a much cleaner way to handle it.
I don't see that there's anything wrong with it. The majority of the rails helpers generate HTML code (which is their purpose) - to me this implies that's what you're supposed to do yourself.
There is however the ever-present issue of code readability. If you have a helper which just builds a big string of raw HTML, then it's going to be hard to understand. While it's fine to generate HTML in helpers, you should do it using things like content_tag, and render :partial rather than just return %Q(<a href="#{something}">#{text}>)
This isn't a full answer to your question, but you can create html in your tags via the content_tag method. My guess as to why would be cleanliness of code.
Also, content_tag allows you to nest tags in blocks. Check out this blog post on content_tag.
On Rails 3 you can use *html_safe* String method to make your helper methods return html tags that won't be escaped.
As mentioned before, helpers are generally thought to be used as business logic, for doing something that drives view code, but is not view code itself. The most conventional place to put things that generate snippets of view code is a partial. Partials can call a helper if needed, but for the sake of keeping things separated, it's best to keep business in the helper and view in the partial.
Also, bear in mind this is all convention, not hard and fast rules. If there's a good reason to break the convention, do what works best.
I put html into partials usually.
Think about semantics. If you put html in a string, you lose the semantic aspect of it: it becomes a string instead of markup. Very different. For example, you cannot validate a string, but you can validate markup.
The reason I wanna put html in a helper instead of partial (and how I found this thread) is terseness. I would like to be able to write =hr instead of =render 'hr'.
To answer the question I didn't ask ;-) : to un-escape HTML in a helper, try this
def hr
raw '<hr />'
end