In MVC/Razor, how can you open a new view instead

2019-07-21 06:42发布

问题:

I have a MVC project with Razor. There is a view with a partial view on the page. I have a button within the partial view that updates the partial view. This works fine. However, I have another button in the view that I want to open a new view; to "break out" of the original view. Instead, this new view opens where the partial page should be. How can I "break out" of the parent view to open a new view?

This come out of my previous question: How do I get my MVC page to post to the same action in IE and Chrome?

Here are the details. I have a view with a partial view. Clicking on the ButtonB gets some data from the database; everything works fine there.

-------------------------------------------------
|                                               |
| MerchantApplicationSummary.cshtml             |
|                                               |
|                                               |
|    PartialDiv                                 |
|    -----------------------------------        |
|    | ApplicationReportPartial.cshtml |        |
|    |                                 |        |
|    |  [Button B]                     |        |
|    -----------------------------------        |
|                                               |
|    [Button A]                                 |
-------------------------------------------------

When I click on Button A, I want to open a brand new view:

-------------------------------------------------
|                                               |
| PrintApplication.cshtml                       |
|                                               |
|                                               |
-------------------------------------------------

Instead, I get the view opening up where the partial view was:

-------------------------------------------------
|                                               |
| MerchantApplicationSummary.cshtml             |
|                                               |
|                                               |
|    PartialDiv                                 |
|    -----------------------------------        |
|    | PrintApplication.cshtml         |        |
|    |                                 |        |
|    -----------------------------------        |
|                                               |
|    [Button A]                                 |
|                                               |
-------------------------------------------------

I think this behavior comes from setting the UpdateTargetId to output the partial page inside a div on the original page. I need this so ApplicationReportPartial opens in the correct spot.

MerchantApplicationSummary.cshtml

@using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "PartialDiv" }))
{
   ...
   <div id="PartialDiv">
   @{
      Html.RenderPartial("ApplicationReportPartial");
    }
  </div>
  ...
}

Here's the controller which checks if it came from button A or button B:

AdminController.cs

    [AuthorizeAdmin]
    [HttpPost]
    public ActionResult MerchantApplicationSummary(string[] ints, FormCollection form, int? page, string submit)
    {
      if (ints != null && (submit == "Print Spanish Application(s)" || submit == "Print Application(s)"))
      {
        return View(@"~/Views/Admin/PrintApplication.cshtml");
      }
    else
    {
      ...
     return PartialView("ApplicationReportPartial", obj_MrntApp);
    }

How do I keep it so that the ApplicationReportPartial opens within MerchantApplicationSummary, but so that PrintApplication opens in a new view?

Edit:

Here's the code for button A:

<input id="Submit" name="submit" type="submit" class="btn btn-primary" value="Print Application(s)" />

I actually did have button A as a action link, but I needed it to make it a submit button to pass along certain values. Here's the action again:

public ActionResult MerchantApplicationSummary(string[] ints, FormCollection form, int? page, string submit)

I need the values of ints when I click on button A; ints is an array of the IDs of checkboxes checked on the page. If I use an action link, how would I pass along those values to the action? -- I did some research and it look like this is not possible (see http://forums.asp.net/t/1470988.aspx?HTML+ActionLink+to+post) so this brings me back to my original question of how to "break out" of the parent view.

回答1:

I solved the problem by doing the following: - In the parent view, I used BeginForm instead of Ajax.BeginForm and left off the UpdateTargetId assignment. - In the controller, returned a View for the partial view instead of a partial view.

MerchantApplicationSummary.cshtml

@using (Html.BeginForm("MerchantApplicationSummary", "Admin"))
{
 ...
 <div id="PartialDiv">
   @{
      Html.RenderPartial("ApplicationReportPartial");
    }
 </div>
 ...
 <input id="Submit" name="submit" type="submit" class="btn btn-primary" value="Print Application(s)" />
}

AdminController.cs

[AuthorizeAdmin]
[HttpPost]
public ActionResult MerchantApplicationSummary(string[] ints, FormCollection form, int? page, string submit, string PrintApplications)
{
  if (ints != null && (submit == "Print Spanish Application(s)" || submit == "Print Application(s)"))
  {
    ...
    return View(@"~/Views/Admin/PrintApplication.cshtml");
  }
  else
  {
    ...
    return View(obj_MrntApp);
  }
}


回答2:

Do a standard form submission and return a redirect response.

MerchantApplicationSummary.cshtml

@(Html.BeginForm("PrintApplication", "Admin", FormMethod.Post)) {
    ...
    <button type="submit" id="buttonA">Print</button>
}

And your controller will be

[HttpPost]
public ActionResult PrintApplication(FormCollection form)
{
    // do stuff with form
    ...
    // stash data you need in redirected view
    TempData["PrintApplication.Id"] = id;

    return RedirectToAction("PrintApplication");
}

[HttpGet]
public ActionResult PrintApplication()
{
    int? id = TempData["PrintApplication.Id"] as int?;
    ViewBag.Id = id.Value;
    return View("PrintApplication");
}

You submit the form and the RedirectToAction returns a 302 Found to the browser and it will redirect to the GET PrintApplication action.

The messy part here is if you need to share the form with your MerchantApplicationSummary AJAX post. It's probably easiest to drop the AjaxHelper.

<div id="appForms">
 @(Html.BeginForm("PrintApplication", "ControllerName",
                  FormMethod.Post), new { id = "formId" }) {

    <div id="PartialDiv">
        @{ Html.RenderPartial("ApplicationReportPartial"); }
    </div>
    ...
    <button type="submit" id="buttonA">Print</button>
 }
</div>

Then wire up the button B to trigger a jquery AJAX post. Make sure button B is not a submit button (e.g. <input type="submit"> or <button type="submit">).

$("#appForms").on("click", "#buttonB", function(event) {
    var data = $("#formId").serialize();
    $.ajax({
        url: "/Admin/MerchantApplicationSummary",
        method: "POST",
        data: data,
        success: function(partialViewResult) {
            $("#PartialDiv").html(partialViewResult);
        }
    });
});

Then remove all PrintApplication logic from MerchantApplicationSummary.

I don't know enough of your specifics so you probably need to do some adjustments here.