TagHelperSamples icon indicating copy to clipboard operation
TagHelperSamples copied to clipboard

Form inside Modal

Open jedielson opened this issue 8 years ago • 2 comments

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'>&times;</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?

jedielson avatar Oct 18 '16 23:10 jedielson

Excellent question. I will need to think through this a little. I don't know the answer off the top of my head

dpaquette avatar Nov 27 '16 00:11 dpaquette

@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>

mguinness avatar Jul 26 '17 05:07 mguinness