简体   繁体   中英

prevent child action from binding to parent ViewData

I have one normal view (NV) and 2 partial views (PV1 and PV2), PV2 is nested in PV1, and PV1 is in NV. The issue i am having is that PV1 and PV2 both have an optional pentameter called "isSuccessful" that is added to the View bag "ViewBag.IsSuccessful = isSuccessful;" in the action, and for some reason when PV1 has its "isSuccessful" set to true PV2's "isSuccessful" is bonded to true as well. This causing PV2 to run some JavaScript functions prematurely causing other issues.

Code (Structure And Example)

in the controller

    public ActionResult NV(int id)
    {
        var model = GetNVModel(id);
        return View(model);
    }

    public ActionResult PV1 (int pv1Id = 0, bool isSuccessful = false)
    {
        var model = GetPV1Model(id);
        ViewBag.IsSuccessful = isSuccessful;
        return PartialView(model);
    }

    public ActionResult PV2 (int pv2Id = 0, bool isSuccessful = false)
    {
        var model = GetPV2Model(id);
        if(model == null){model = new PV2Model();}
        ViewBag.IsSuccessful = isSuccessful;
        return PartialView(model);
    }

The Views

NV.cshtml

     @model NVModel
     <div>
         @if (Model != null && Model.PV1Id != null && Model.PV1Id > 0)
         {<text>
              @Html.Action("PV1", "ControlerName", new { PV1Id = Model.PV1Id, isSuccessful = true})
         </text>}
     </div>

PV1.cshtml

     @model PV1Model
     @{bool isSuccessful = (ViewBag.IsSuccessful != null ? (bool)ViewBag.IsSuccessful : false);}
     <div>
         @if (Model != null && Model.PV2Id != null && Model.PV2Id > 0)
         {<text>
              @Html.Action("PV2", "ControlerName", new { PV2Id = Model.PV2Id })
         </text>}
     </div>
     <script>
         @if (isSuccessful )
         {<text>
              function sayHello()
              {console.log('Hello PV1');}
         </text>}
     </script>

PV2.cshtml

     @model PV2Model
     @{bool isSuccessful = (ViewBag.IsSuccessful != null ? (bool)ViewBag.IsSuccessful : false);}
     <div>
         @if (Model != null)
         {<text>
              @Html.TextBoxFor(model=> model.Message)
         </text>}
     </div>
     <script>
         @if (isSuccessful )
         {<text>
              $(document).ready(function(){
                 console.log($("#Message").val());
              });
         </text>}
     </script>

What I don't understand is why PV1's ViewData/ViewBag Is being passed to PV2. I thought that not passing all of the parent ViewData/ViewBag was part of the point of using "@Html.Action" over "@Html.Partial". What I need to know is if there is a parameter I need to pass in to "@Html.Action" or a web.config attribute needs to be flipped , because the above is not just a one time thing, it is the way i have been doing most of my pages in order to make the views as flexible as possible.

I am using ASP.NET MVC 4, C#, and .NET 4.5

Thanks for any help or clues to this issue.

ViewBag is not shared between the actions, however the route parameters are! You can see this if you set a breakpoint inside the PV2 method and check the ViewBag before executing ViewBag.IsSuccessful = isSuccessful; . You will see that the ViewBag is empty but the method received the parameter as true.

The problem is that you are passing a route parameter isSuccessful to PV1 with @Html.Action("PV1", "ControlerName", new { PV1Id = Model.PV1Id, isSuccessful = true}) so when you call the PV2 action the route attributes for PV2 are merged with the current ones. That means isSuccessful will be passed to PV2.

If you check the MVC source code for the Html.Action helper, you will see that the route attributes are merged with the current ones. Check the internal ActionHelper method, where the merge is happening:

internal static void ActionHelper(HtmlHelper htmlHelper, string actionName, string controllerName, RouteValueDictionary routeValues, TextWriter textWriter)
{
    ...

    //The route values provided to @Html.Action are merged with the current ones
    RouteValueDictionary additionalRouteValues = routeValues;
    routeValues = MergeDictionaries(routeValues, htmlHelper.ViewContext.RouteData.Values);

    ...
}

If you want to prevent this, you can override the route parameter when calling PV2. For this you can do the following:

@Html.Action("PV2", "Home", new { isSuccessful = "" })

You could also call the action using the RouteValueDictionary which would let you set the route parameter as null:

@Html.Action("PV2", "Home", new RouteValueDictionary{{"isSuccessful", null}})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM