Use TagHelper inside another TagHelper - asp.net-core

I have build a custom tag helper that dynamicaly build a form with input tags.
Example
foreach(var foo in foos)
{
htmlOutput += $"<input asp-for='{foo.FieldName}' />";
}
then i want to model bind this, but my custom tag helper output the asp-for attribute instead of model bind it, probably because im trying to use a tag helper inside my custom tag helper. Any way to get around this?

Related

Razor template/component solution that supports child Razor markup

Is there a template/component solution in ASP.NET Core Razor, that supports inner Razor markup?
Here's a use case:
1. Say I have some repetitive markup for example "a div with nice borders, shadows and two buttons at the bottom"
2. Obviously this markup has a common "header" and a "footer" in the HTML code
3. I need to pass arbitrary Razor markup to insert between header and footer. Not just a model object - but some actual markup that will be rendered between header and footer. I can't use foreach because this markup is different every time - it can be text-content, a form, an image, or some complicated Razor-rendered stuff.
Basically I'm looking for a "Surround this Razor with more Razor" templating solution
Something like:
#{
//this function renders my beautiful box
Func<dynamic, IHtmlContent> myFunction = #<div class="relative flex flex-col rounded-2xl border border-gray-200 bg-white p-8 shadow-sm">
#item
</div>;
}
<!-- and then I call it passing some Razor as input -->
#myFunction(
<ul>
<li>#SomeRazorMethod()</li>
</ul>
);
Something like a Layout - but the one I can use multiple times on the same page.
Is there anything like that? This is a pretty common componentizing tool - "wrap my markup with other markup" - that is present in other templating engines (React, Vue, etc), but apparently not in Razor.
Just to be clear: I'm looking for a Razor-based solution, not a C#-based one. So that my header-footer markup stays in markup files (.cshtml), not in C# files that will have hard-coded HTML magic strings.
Based on your example, this might help.
#functions {
public static IHtmlContent MyBox(dynamic item, Func<dynamic, IHtmlContent> template)
{
var html = new HtmlContentBuilder();
html.AppendHtml("<div class='bestcss'>");
html.AppendHtml(template(item));
html.AppendHtml("</div>");
return html;
}
}
#MyBox(null, #<div class='innercss'>#(10 == 12 ? "MyTest Equals" : "No Equal") hello</div>)
And if you like to pass modeldata, it will be:
#MyBox(customerdata, #<div class='innercss'>#(10 == 12 ? "MyTest Equals" : "No Equal") hello #item.FirstName</div>)
I have used some arbitrary if condition for testing.
You can use Partial Pages or Views which are Razor files containing snippets of HTML and server-side code to be included in any number of pages or layouts.
Just like standard Razor pages, partial pages support the #model
directive specifying the type for the partial's data model. All of the
rendering methods have overloaded versions that take a model to be
consumed in the partial.
#Shah's answer got me one step closer to a solution, however, it seems like the the actual question I'm trying to solve is "can I pass Razor markup as an input parameter".
Turns out you can, you just have to put # in front of it:
#{
void MyFunc(Func<object, IHtmlContent> template)
{
<div>#template(null)</div>
}
}
#{ MyFunc(#<div>The ID is: #Model.Id</div>); }
<!-- mind the '#' before the 'div' -->

How do I allow my ASP.NET Core tag helpers to be self-closing

I have written a tag helper that I can use as follows...
<mytaghelper attr1="jim"></mytaghelper>
I would like to be able to shorten this to just...
<mytaghelper attr1="jim">
...or at least...
<mytaghelper attr1="jim"/>
However, I can't get this to work. Here is some sample code for the Process method...
public override void Process(TagHelperContext context, TagHelperOutput output) {
output.TagName = "div";
output.PreContent.SetHtmlContent("<div>");
output.Content.SetHtmlContent("OUTPUT HTML GOES HERE");
output.PostContent.SetHtmlContent("</div>");
output.Attributes.Clear();
}
I have tried adding a TagStructure setting to the HtmlTargetElement attribute on the class...
[HtmlTargetElement("mytaghelper", TagStructure = TagStructure.WithoutEndTag)]
...but it doesn't seem to make any difference. <mytaghelper attr1="jim"/> generates <div /> and <mytaghelper attr1="jim"></mytaghelper> generates <div></mytaghelper>.
If I set the TagStructure to NormalOrSelfClosing then included a closing tag works, but <mytaghelper attr1="jim"/> gives an empty <div />
Anyone able to explain what I need to do?
TagStructure.WithoutEndTag is able to write the tag with only a start tag or self-closing, but the output would be <div > or <div/> . Self-closing anchor tags are not valid HTML, so you wouldn't want to create one, but you might want to create a tag helper that's self-closing. Tag helpers set the type of the TagMode property after reading a tag. Add the below code line Inside the process method:
output.TagMode = TagMode.StartTagAndEndTag;
Take a moment to read Author Tag Helpers in ASP.NET Core which covers this perfectly .
The correct syntax is:
[HtmlTargetElement("mytaghelper", TagStructure = TagStructure.WithoutEndTag)]
Which should be applied to the taghelper class, not the Process method. You may already be doing that, but it wasn't clear in your question. I believe you still must use the self-closing tag syntax (/>) for it work, though.

Input Mask in ASP MVC Core using DisplayMetadata Provider

I was trying to find a way to implement Input Mask by passing custom attribute from Model Class in MVC ASP NET Core and built HTML attribute accordingly into HTML element .below is the answer
I would like to share with you on how you apply the Input Mask using DisplayMetadata Provider as it is different than other version.
Here are brief steps more info on this can be find it in this link: In MVC Core Passing custom attribute from Model class to HTML element "e.g.:Input Masking" https://www.codeproject.com/Tips/1243346/In-MVC-Core-Passing-custom-attribute-from-Model-cl
1- Create Custom Attribute e.g.:HTMLMaskAttribute , inherit from Attribute Class
2- Create custom DisplayMetadataProvider by implementing the interface IDisplayMetadataProvider , this provider will read the new attribute from the model class .
3-register CustomMetadataProvider in the startup class of MVC application
4-In Model Class add the new custom attribute "mask" in the property you need to create a mask of it example Phone number.
5- I am using Masked Input Plugin for my example download it and include the jQuery and masked input javascript files to your specific view page or to your _Layout.cshtml page .
6- add this script into your view either _layout.cshtml or specific view :
<script type="text/javascript">
$(function () {
$('[mask]').each(function (e) {
$(this).mask($(this).attr('mask'));
});
});
</script>
7- create the view and include the Property that has an attribute
8- Run the application and notice the html attribute mask has been added for to the property Phone1
<input name="Phone1" class="form-control valid" id="Phone1" aria-invalid="false" type="text" value="(123) 456-7890" mask="(999) 999-9999">

Is there a HTML helper that generates something like a label but with an ID attribute in MVC4?

I need to generate some html, that I can access later from Jquery to inject a value later on. On initial rendering, it should not show anything. I am using MVC4.
Maybe something like
Is there a HTML helper? or do I need to create my own? if so, how do I go about it?
Thanks
You just need to pass HtmlAttributes as parameters for the out-of-the-box MVC4 Helpers.
#Html.Label("", new { id = "yourID"})
But, maybe you just need a <span id="yourID"></span>
And you only need a helper for this, if you pretend to use it several times.
If you want to create an helper extension:
public static MvcHtmlString CustomLabel(this HtmlHelper helper, string labelId, string content = "")
{
var span= new TagBuilder("span");
span.Attributes.Add("id", labelId);
span.SetInnerText(content)
return MvcHtmlString.Create(span.ToString());
}
You could add another parameters to set CSS class or something like that.
Then, in your view you use it like this:
#Html.CustomLabel("yourID", "Initial Text")
EDIT: For strongly typed Html Helpers see this:
http://www.codeproject.com/Tips/389747/Custom-Strongly-typed-HtmlHelpers-in-ASP-NET-MVC
Any way, in your case, would just create one this way: #Html.CustomLabel(m=>m.YourID, "Initial Value") so that if you have the Initial Value in the model, you can do Model.InitValue instead of harcoding it like I did previously.

How to show/hide div in WinJS Template dynamically

I have a Windows 8 app with a template that contains a div I want to show or hide based on the value of a property inside a data-win-control="WinJS.Binding.Template". I have tried the following without luck:
<div data-win-bind="visible: isMore"> ..content... </div>
where isMore is a boolean property of the databound item.
How can I do that? I guess the visible property does not exist?
You are right - the visible property doesn't exist, but you can control the appearance using CSS and a binding converter.
First, use WinJS.Binding.converter to create a converter function that translates a boolean to a value value for the CSS display property, like this:
var myConverter = WinJS.Binding.converter(function (val) {
return val ? "block" : "none";
});
Make sure that the function is globally available - I use WinJS.Namespace.define to create collections of these converters that I can get to globally.
Now you can use the converter in your data binding to control the CSS display property, like this:
<div data-win-bind="style.display: isMore myConverter"> ..content... </div>