TagHelperSamples
TagHelperSamples copied to clipboard
Form inside Modal
How can we have an structure like this?
<modal title="Modal title">
<form asp-controller="Controller" asp-action="Action" method="post">
<modal-body>
<div class="form-horizontal">
<div class="form-group">
<label asp-for="Nome" class="control-label col-md-2">Nome:</label>
<div class="col-md-10">
<input asp-for="Nome" type="text" class="form-control" />
</div>
</div>
</div>
</modal-body>
<modal-footer>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</modal-footer>
</form>
</modal>
The modal was correctly generated, but the form was removed (as expected). I've tried to create another custom helper to form like
/// <summary>
/// A Bootstrap modal dialog
/// </summary>
[RestrictChildren("modal-body", "modal-footer", "form")]
public class ModalTagHelper : TagHelper
{
/// <summary>
/// The title of the modal
/// </summary>
public string Title { get; set; }
/// <summary>
/// The Id of the modal
/// </summary>
public string Id { get; set; }
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var modalContext = new ModalContext();
context.Items.Add(typeof(ModalTagHelper), modalContext);
await output.GetChildContentAsync();
var template =
$@"<div class='modal-dialog' role='document'>
<div class='modal-content'>
<div class='modal-header'>
<button type = 'button' class='close' data-dismiss='modal' aria-label='Close' modal-close-action><span aria-hidden='true'>×</span></button>
<h4 class='modal-title' id='{context.UniqueId}Label'>{Title}</h4>
</div>
<div class='modal-body'>";
output.TagName = "div";
output.Attributes.SetAttribute("role", "dialog");
output.Attributes.SetAttribute("id", Id);
output.Attributes.SetAttribute("aria-labelledby", $"{context.UniqueId}Label");
output.Attributes.SetAttribute("tabindex", "-1");
var classNames = "modal fade";
if (output.Attributes.ContainsName("class"))
{
classNames = string.Format("{0} {1}", output.Attributes["class"].Value, classNames);
}
output.Attributes.SetAttribute("class", classNames);
output.Content.AppendHtml(template);
if (modalContext.Body != null)
{
output.Content.AppendHtml(modalContext.Body);
}
output.Content.AppendHtml("</div>");
if (modalContext.Footer != null)
{
output.Content.AppendHtml("<div class='modal-footer'>");
output.Content.AppendHtml(modalContext.Footer);
output.Content.AppendHtml("</div>");
}
output.Content.AppendHtml("</div></div>");
}
}
/// <summary>
/// The modal-footer portion of Bootstrap modal dialog
/// </summary>
[HtmlTargetElement("modal-footer", ParentTag = "modal")]
[HtmlTargetElement("modal-footer", ParentTag = "form")]
public class ModalFooterTagHelper : TagHelper
{
/// <summary>
/// Whether or not to show a button to dismiss the dialog.
/// Default: <c>true</c>
/// </summary>
[HtmlAttributeName("show-dismiss")]
public bool ShowDismiss { get; set; } = true;
/// <summary>
/// The text to show on the Dismiss button
/// Default: Cancel
/// </summary>
[HtmlAttributeName("dismiss-text")]
public string DismissText { get; set; } = "Cancel";
/// <summary>
/// A classe CSS a ser aplicada no botão de dismiss.
/// Não é necessário aplicar btn
/// </summary>
[HtmlAttributeName("dismiss-css-class")]
public string DismissCssClass { get; set; } = "btn-default btn-100";
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (ShowDismiss)
{
output.PreContent.AppendFormat(@"<button type='button' class='btn {0}' data-dismiss='modal' modal-close-action>{1}</button>", DismissCssClass, DismissText);
}
var childContent = await output.GetChildContentAsync();
var footerContent = new DefaultTagHelperContent();
if (ShowDismiss)
{
footerContent.AppendFormat(@"<button type='button' class='btn {0}' data-dismiss='modal' modal-close-action>{1}</button>", DismissCssClass, DismissText);
}
footerContent.AppendHtml(childContent);
var modalContext = (ModalContext)context.Items[typeof(ModalTagHelper)];
modalContext.Footer = footerContent;
output.SuppressOutput();
}
}
/// <summary>
/// The modal-body portion of a Bootstrap modal dialog
/// </summary>
[HtmlTargetElement("modal-body", ParentTag = "modal")]
[HtmlTargetElement("modal-body", ParentTag = "form")]
public class ModalBodyTagHelper : TagHelper
{
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
var childContent = await output.GetChildContentAsync();
var modalContext = (ModalContext)context.Items[typeof(ModalTagHelper)];
modalContext.Body = childContent;
output.SuppressOutput();
}
}
But had no success...
How can I fix it?
Excellent question. I will need to think through this a little. I don't know the answer off the top of my head
@jedielson Keep the form in modal-body and the button outside in modal-footer. Then you can either use the new HTML5 form attribute or just add the following to your button to trigger the submit:
<button type="button" onclick="document.forms[0].submit()">Save changes</button>