HtmlHelper on ActionLink in Razor - razor

I use MVC3 Razor and have a link
Edit
I have written HtmlHelper
public static MvcHtmlString MyHelper(this HtmlHelper helper, string name, string href, string #class = null)
{
var builder = new TagBuilder("a");
builder.MergeAttribute("href", href);
builder.AddCssClass(#class);
builder.InnerHtml = name;
return new MvcHtmlString(builder.ToString());
}
and this link is bad
#Html.MyHelper("Edit","#Url.Action('Edit', 'Obj', new { id = RSAuth.UserId })", "gray-butt right")

Can you try this?
#Html.MyHelper("Edit",Url.Action('Edit', 'Obj', new { id = RSAuth.UserId }), "gray-butt right")
remove the quote for Url.Action, because it is a function that return a string

Related

Adding a dynamic list of parameters with Html helper

I'd like to be able to feed in a list of parameter names and values into a Html.Actionlink but the helper doesn't create the parameters as I would like. Any ideas how to do this?
public class ParameterNameValue
{
public string ParameterName { get; set; }
public string ParameterValue { get; set; }
}
View
#foreach (var action in post.FeedActions)
{
var parameters = "";
foreach (var param in action.Parameters)
{
parameters += param.ParameterName + "=" + param.ParameterValue + ",";
}
#Html.ActionLink(#action.Label, action.ActionName,
new { controller = action.Controller, id = action.CommunityId, slug = action.Slug,
Fromfeed=true,parameters }, new { #class = action.Classes })
}
yields a link like this:
Whereas I need the parameters part to look like:
?FromFeed=true&MatchId=1234&InnerId=5678
edit: I got it working by just manually creating the tag, but no doubt there's a nice way of doing this by creating a custom helper.
#action.Label
I'd suggest you to extend the classic ActionLink helper with a prototype similar to this (add a parameter for your specific class) :
public static MvcHtmlString ActionLinkCustom(this HtmlHelper html, string linkText, string actionName, string controllerName, object routeValues, List<ParameterNameValue> yourOtherValues)
In the code, check if you got any custom values. If such, add them to the RouteValuesDictionnary. Then use the classic ActionLink helper providing this modified RouteValuesDictionnary.
Note : you can work on the routeValues using this
IDictionary<string, object> RouteValues = HtmlHelper.ObjectToDictionary(routeValues);

render the view using razorengine mvc

I am using RazorEngine to get the view and load it as html.but however my problem is I am reading html code from my database,and show it on my web page .but it gave me string result on my web page rather then html output.
how can I solve this problem
thank you in advace
My simple view like this
#model Cms.ViewModules.MasterPageViewModel
#Model.PageLanguageViewModel.HtmlCode
and this is how get the view as html from my views
public static class HtmlHelperPageContent
{
public static IHtmlString GetPageAll(this HtmlHelper htmlHelper, MasterPageViewModelmodel)
{
string page = model.PageLanguageViewModel.SablonHtlmCodu;
List<string> registeredModules = PageModulles.RegisteredModules;
foreach (var modulename in registeredModules )
{
string fullmodulename = "${" + modulename + "}";
if (page.Contains(fullmodulename ))
{
string viewname = modulename.Insert(0, "PW_");
IHtmlString value = RenderViewHelper.RenderPartialToString("Views/Default/" + viewname + ".cshtml", model);
page=page.Replace(fullmodulename , value.ToHtmlString());
}
}
return MvcHtmlString.Create(page);
}
RenderViewHelper class
public static class RenderViewHelper
{
public static IHtmlString RenderPartialToString(string viewPath, object model)
{
string viewAbsolutePath = MapPath(viewPath);
var viewSource = File.ReadAllText(viewAbsolutePath);
string renderedText = Razor.Parse(viewSource, model);
return new MvcHtmlString(renderedText);
}
}
Another way would be to use IEncodedString (https://github.com/Antaris/RazorEngine/blob/master/src/source/RazorEngine.Core/Text/IEncodedString.cs) instead of IHtmlString by creating a RawString (https://github.com/Antaris/RazorEngine/blob/master/src/source/RazorEngine.Core/Text/RawString.cs) instance.
#Raw does exactly that behind the scenes (https://github.com/Antaris/RazorEngine/blob/master/src/source/RazorEngine.Core/Templating/TemplateBase.cs#L147).
#Raw(#Model.PageLanguageViewModel.HtmlCode) solved my problem

How does Asp.net Core renders a view

How does MVC 6 renders a view. What's the actual method in Razor ViewEngine that generates the html output? Also if possible please explain the process of rendering a view.
May be you could point me to a file on mvc source on github. thanks!
Here is a complete solution of what you are looking for. I used dependency injection to get the HtmlHelper in the controller. You can inject your own helper if you want too.
using Microsoft.AspNet.Html.Abstractions;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.ViewEngines;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Mvc.ViewFeatures.Internal;
using Microsoft.Extensions.WebEncoders;
using System.ComponentModel.DataAnnotations;
using System;
public class MyController : Controller
{
private readonly IHtmlGenerator htmlGenerator;
ICompositeViewEngine viewEngine;
IModelMetadataProvider metadataProvider;
private readonly IHtmlHelper helper;
IHtmlEncoder htmlEncoder;
IUrlEncoder urlEncoder;
IJavaScriptStringEncoder javaScriptStringEncoder;
public MyController(IHtmlHelper helper, IHtmlGenerator htmlGenerator, ICompositeViewEngine viewEngine, IModelMetadataProvider metadataProvider, IHtmlEncoder htmlEncoder, IUrlEncoder urlEncoder, IJavaScriptStringEncoder javaScriptStringEncoder)
{
this.htmlGenerator = htmlGenerator;
this.viewEngine = viewEngine;
this.metadataProvider = metadataProvider;
this.htmlEncoder = htmlEncoder;
this.urlEncoder = urlEncoder;
this.javaScriptStringEncoder = javaScriptStringEncoder;
this.helper = helper;
}
[HttpGet]
public IActionResult MyHtmlGenerator()
{
MyViewModel temp = new MyViewModel();
var options = new HtmlHelperOptions();
options.ClientValidationEnabled = true;
ViewDataDictionary<MyViewModel> dic = new ViewDataDictionary<MyViewModel>(this.metadataProvider, new ModelStateDictionary());
ViewContext cc = new ViewContext(ActionContext, new FakeView(), dic, TempData, TextWriter.Null, options);
var type = typeof(MyViewModel);
var metadata = this.metadataProvider.GetMetadataForType(type);
ModelExplorer modelEx = new ModelExplorer(this.metadataProvider, metadata, temp);
ViewData["Description"] = "test desc";
ViewData["Id"] = 1;
this.ViewData = new ViewDataDictionary(this.metadataProvider, new ModelStateDictionary());
IHtmlHelper<MyViewModel> dd = new HtmlHelper<MyViewModel>(this.htmlGenerator, this.viewEngine, this.metadataProvider, this.htmlEncoder, this.urlEncoder, this.javaScriptStringEncoder);
((ICanHasViewContext)dd).Contextualize(cc);
dd.ViewContext.ViewData = this.ViewData;
var desc = GetString(dd.TextBoxFor(m => m.ID));
var ID = GetString(dd.TextBoxFor(m => m.Description));
// Do whatever you want with the ID and desc
return new ContentResult() { Content = ID + desc };
}
public static string GetString(IHtmlContent content)
{
var writer = new System.IO.StringWriter();
content.WriteTo(writer, new HtmlEncoder());
return writer.ToString();
}
}
public class MyViewModel : BaseAssetViewModel
{
// [RegularExpression(#"^-?\d{1,13}(\.\d{0,5})?$|^-?\.\d{1,5}$")]
[Required]
public int ID { get; set; }
[MinLength(2)]
public string Description { get; set; }
// Property with no validation
public string Other { get; set; }
}
public class FakeView : IView
{
string IView.Path
{
get
{
throw new NotImplementedException();
}
}
public Task RenderAsync(ViewContext viewContext)
{
throw new InvalidOperationException();
}
Task IView.RenderAsync(ViewContext context)
{
throw new NotImplementedException();
}
}
I don't know if this may be of help, may be you have to start to look at tag helpers:
https://github.com/DamianEdwards/TagHelperStarterWeb
they're working to a different way to create helpers that integrate in the page in a more natural way.

MVC3 - Razor: How to use html tag in ActionLink Name

I have a action link on my MVC3 razor view. Which have a action link as bellow:
#Html.ActionLink("Click Here (I do not have Middle Name)",
"", "", new { #class = "button lines-6" })
I want to change action link text to:
<strong>Click Here </strong> (I do not have Middle Name)
Is there any way to sort it out.
Many Thanks
Using the URL.Action instead of an action link you have more control over the contents.
<a href="#Url.Action("Index", "Home")" class="button lines-6">
<strong>Click Here </strong> (I do not have Middle Name)
</a>
A custom HtmlHelper extension is another option.
public static string ActionLinkSpan( this HtmlHelper helper, string linkText, string actionName, string controllerName, object htmlAttributes )
{
TagBuilder spanBuilder = new TagBuilder( "span" );
spanBuilder.InnerHtml = linkText;
return BuildNestedAnchor( spanBuilder.ToString(), string.Format( "/{0}/{1}", controllerName, actionName ), htmlAttributes );
}
private static string BuildNestedAnchor( string innerHtml, string url, object htmlAttributes )
{
TagBuilder anchorBuilder = new TagBuilder( "a" );
anchorBuilder.Attributes.Add( "href", url );
anchorBuilder.MergeAttributes( new ParameterDictionary( htmlAttributes ) );
anchorBuilder.InnerHtml = innerHtml;
return anchorBuilder.ToString();
}
You may also try a different flavor of above suggested option:
<li id="home_nav"><span>Span text</span></li>

How to disable input field's autocomplete with EditorFor?

<%= Html.EditorFor(product => product.Name) %>
I need the generated output to have autocomplete="off" attribute set.
What I'm missing?
Edit:
I'm looking an extension method for EditorFor that accepts key/value dictionary for attributes, so I can call it like this: <%= Html.EditorFor(product => product.Name, new { autocomplete = "off" } ) %>
Here it is done for LabelFor, but it is needed to be adjusted for EditorFor
public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes) {
return LabelFor(html, expression, new RouteValueDictionary(htmlAttributes));
}
public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IDictionary<string, object> htmlAttributes)
{
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
string htmlFieldName = ExpressionHelper.GetExpressionText(expression);
string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
if (String.IsNullOrEmpty(labelText))
{
return MvcHtmlString.Empty;
}
TagBuilder tag = new TagBuilder("label");
tag.MergeAttributes(htmlAttributes);
tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));
tag.SetInnerText(labelText);
return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
}
Edit2:
I realized it can't be named EditorFor because there already exists an overridden EditorFor that accepts an anonymous type, see here http://msdn.microsoft.com/en-us/library/ff406462.aspx.. anyway, we can name it differently, no biggies.
You'll need to use use a custom template that generates the input element with the attribute or you could add some javascript to the page to add the attribute client-side.
<%= Html.EditorFor( product => product.Name, "NoAutocompleteTextBox" ) %>
Then in Shared/EditorTemplates you need a NoAutocompleteTextBox.ascx that defines
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%= Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue,
new { autocomplete = "off" }) %>
or, the jQuery way, to set it on all text inputs
$(function() {
$('input[type=text]').attr('autocomplete','off');
});
public static MvcHtmlString EditorForAttr<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes) {
return EditorForAttr(html, expression, new RouteValueDictionary(htmlAttributes));
}
public static MvcHtmlString EditorForAttr<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IDictionary<string, object> htmlAttributes) {
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
string htmlFieldName = ExpressionHelper.GetExpressionText(expression);
TagBuilder tag = new TagBuilder("input");
tag.GenerateId(html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));
tag.MergeAttribute("name", htmlFieldName);
tag.MergeAttribute("type", "text");
tag.MergeAttribute("value", metadata.Model == null ? "" : metadata.Model.ToString()); // Not sure if this is correct.
tag.MergeAttributes(htmlAttributes, true);
return MvcHtmlString.Create(tag.ToString(TagRenderMode.SelfClosing));
}