0

This could be considered a continuation to this question since I used the accepted answer as a base. However, I'd like to know if anyone has a working solution as to how to return a result to the Modal window opened through an Ajax/PartialView-Result.

My base view:

<div id="addNewModal" class="modal fade in" data-url="@AjaxAddNewUri"> //AjaxAddNewUri is defined as a variable in the view
    <div id="addNewContainer">
    </div>
</div> 

function fnAddNew()
{
    var url = $('#addNewModal').data('url');

    $.get(url, function (data)
    {
        $('#addNewContainer').html(data);
        $('#addNewModal').modal('show');
    });
}

My partial view:

@model MyModel

<form asp-controller="My" asp-action="@nameof(MyController.AjaxAddNew)" asp-antiforgery="true" method="post" class="form-horizontal">
    <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"><span aria-hidden="true">&times;</span></button>
                <h4 class="modal-title" id="AddNew">Add New Title </h4>
            </div>
            <div class="modal-body">
                <div asp-validation-summary="All" class="text-danger"></div>
                <div class="form-group">
                    <label asp-for="SomeProperty" class="col-md-3 control-label"></label>
                    <div class="col-md-9">
                        <input asp-for="SomeProperty" class="form-control" />
                        <span asp-validation-for="SomeProperty" class="text-danger"></span>
                    </div>
                </div>
                //other form-group...
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                <button type="submit" class="btn btn-primary">Save changes</button>
            </div>
        </div>
    </div>
</form>

Now, suppose I have an Action like this:

[HttpPost]
[Route("/MyCustomRoute")]
[ForceAjax] //custom attribute that ensures it comes from AJAX otherwise kills the request
public async Task<IActionResult> AjaxAddNew(MyModel model)
{
    if (!ModelState.IsValid)
        return PartialView(model);
    return PartialView(model);
}

I would expect the modal to be updated with the Model errors, but instead I get a blank page, what am I doing wrong here? If it matters, the "base" view is a PartialView inside a PartialView inside a View.

Update

I realized that the JQuery Unobtrusive Ajax script was not loading as expected, making the call with HTTP instead of AJAX, hence returning a redirect as per the [ForceAjax] attribute I use. However, once I got it working, the modal window is still not updating - the errors in the model do not show up as they should. Here is the rendered HTML:

<form data-ajax="true" data-ajax-method="POST" class="form-horizontal" action="/My/AjaxAddNew" method="post">
    <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"><span aria-hidden="true">×</span></button>
                <h4 class="modal-title" id="AddNew">Add New Title </h4>
            </div>
            <div class="modal-body">
                <div class="text-danger validation-summary-valid" data-valmsg-summary="true"><ul><li style="display:none"></li>
</ul></div>
                <div class="form-group">
                    <label class="col-md-3 control-label" for="SomeProperty">SomeProperty</label>
                    <div class="col-md-9">
                        <input class="form-control" type="text" data-val="true" data-val-number="The field SomeProperty must be a number." data-val-range="The field SomeProperty must be between 0,1 and ∞." data-val-range-max="Infinity" data-val-range-min="0.1" data-val-required="SomeProperty is required" id="SomeProperty" name="SomeProperty" value="0">
                        <span class="text-danger field-validation-valid" data-valmsg-for="SomeProperty" data-valmsg-replace="true"></span>
                    </div>
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                <button type="submit" class="btn btn-primary">Save changes</button>
            </div>
        </div>
    </div>
<input name="__RequestVerificationToken" type="hidden" value="....."></form>

POSTing the form makes absolutely no changes to the HTML, why?

Community
  • 1
  • 1
Camilo Terevinto
  • 31,141
  • 6
  • 88
  • 120
  • in the demo app for my [pagination taghelper](https://github.com/joeaudette/cloudscribe.Web.Pagination), I have a working bootstrapmoadltaghelper, and the demo app does pagination inside a modal loaded as a partial view, and the pagination happens with ajax and another partial view loaded from within the modal partial – Joe Audette Aug 28 '16 at 14:02
  • @JoeAudette I'm sorry, how would that help me? At which file(s) should I be looking at? – Camilo Terevinto Aug 28 '16 at 14:04
  • have you set a breakpoint in that action and stepped through to verify it is executing that code? and verify the model is as expected? a blank page can be a 404 – Joe Audette Aug 28 '16 at 19:46
  • @JoeAudette I started looking at this in fact right before you posted it, and yes, for some reason the URL the form is posting to is corrupt or rather pointing to another form's URL – Camilo Terevinto Aug 28 '16 at 21:16

2 Answers2

2

My solution uses jquery unobtrusive ajax. I created a taghelper that adds the data-* attributes needed for unobtrusive ajax to open the modal, so using my tag helper, the anchor to open the modal is like this:

<a class="btn btn-xs btn-default" 
   asp-action="IndexAjax" asp-controller="Paging"
   bs-modal-link="true">Ajax Modal</a>

The code for the taghelper itself is:

using Microsoft.AspNetCore.Razor.TagHelpers;
using System;

namespace PagingDemo.Web.TagHelpers
{

    [HtmlTargetElement("a", Attributes = BootstrapModalLinkAttributeName)]
    public class BootstrapModalAnchorTagHelper : TagHelper
    {
        private const string BootstrapModalLinkAttributeName = "bs-modal-link";

        public BootstrapModalAnchorTagHelper() : base()
        {

        }

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            // we don't need to output this attribute it was only used for matching in razor
            TagHelperAttribute modalAttribute = null;
            output.Attributes.TryGetAttribute(BootstrapModalLinkAttributeName, out modalAttribute);
            if (modalAttribute != null) { output.Attributes.Remove(modalAttribute); }

            var dialogDivId = Guid.NewGuid().ToString();
            output.Attributes.Add("data-ajax", "true");
            output.Attributes.Add("data-ajax-begin", "prepareModalDialog('" + dialogDivId + "')");
            output.Attributes.Add("data-ajax-failure", "clearModalDialog('" + dialogDivId + "');alert('Ajax call failed')");
            output.Attributes.Add("data-ajax-method", "GET");
            output.Attributes.Add("data-ajax-mode", "replace");
            output.Attributes.Add("data-ajax-success", "openModalDialog('" + dialogDivId + "')");
            output.Attributes.Add("data-ajax-update", "#" + dialogDivId);

        }
    }
}

For it to work it requires the jquery unobtrusive ajax script to be in the page along with this script which wires up the modal

The partial view used in the IndexAjax action is here. You can see that it uses another partial view to load a pageable grid

I recommend clone or download my project and try the demo to see the ajax modal working then study it further and apply the same concepts to get your working

Joe Audette
  • 35,330
  • 11
  • 106
  • 99
  • This does not show how to update an already opened modal, if so please tell me specifically which view from your example – Camilo Terevinto Aug 28 '16 at 19:18
  • And by that I mean to update from a Controller a modal by returning a PartialView to it, I know how to load a PartialView to **show** the modal – Camilo Terevinto Aug 28 '16 at 19:19
  • you asked "I'd like to know if anyone has a working solution as to how to return a result to the Modal window opened through an Ajax/PartialView-Result" I provided a working example that does that, you can study the code in my example, there is no magic to returning a partial view, you can see my [controller actions here](https://github.com/joeaudette/cloudscribe.Web.Pagination/blob/master/src/PagingDemo.Web/Controllers/PagingController.cs) I've done my best to help you, that is all I can do – Joe Audette Aug 28 '16 at 19:42
0

seems like you are returning some static view without any model no mater what happens in this method:

[HttpPost]
[Route("/MyCustomRoute")]
[ForceAjax] //custom attribute that ensures it comes from AJAX otherwise kills the request
public async Task<IActionResult> AjaxAddNew(MyModel model)
{
    if (!ModelState.IsValid)
        return PartialView();
    return PartialView();
}

instead I would think the Partial view needs the model passed into it like this:

[HttpPost]
[Route("/MyCustomRoute")]
[ForceAjax] //custom attribute that ensures it comes from AJAX otherwise kills the request
public async Task<IActionResult> AjaxAddNew(MyModel model)
{
    if (!ModelState.IsValid)
        return PartialView(model);
    return PartialView(model);
}

in order for it to have any content from the model

Joe Audette
  • 35,330
  • 11
  • 106
  • 99
  • The action it's just an example, it does much more than just check if the model is valid or not, but I forgot to add the model to the return, you are right there – Camilo Terevinto Aug 28 '16 at 19:37