简体   繁体   中英

When overloading a Controller that returns a View, how should I load different content based on a ViewBag property?

I have 2 Index functions,

public ActionResult Index ( )
{
 ...
}

and

[HttpPost]
public ActionResult Index (HttpPostedFileBase file, string selectedOrgName, string selectedCatName)
{
 ...
}

The second method adds a particular object:

ViewBag.orgcatJSON = PD.mapOrgs2Cats();

to the ViewBag , while the first method doesn't. If I've called the second method, I need to use Javascript to do something with that object; if I've called the first method, I don't. So what I'm doing is

var ogmap = @Html.Raw(@ViewBag.orgcatJSON);
$(function() {
    if (ogmap != undefined)
    {
       // do something
    }
});

but that seems like very bad form. Is there a better way of doing this?

If you want to have different content in your view depending on the method, then do just that and use two views. You can then use partials for the related content to keep things DRY .

A major advantage to separating the views like this is that you've made your dependencies (a ViewBag variable in this case) much clearer. In your example, you would have to dig all the way into the javascript to spot that detail which could take some time. As a rule of thumb, I always try to keep my views as stupid as possible (ie as little logic as necessary to complete the task).

For example:

Controllers/ExampleController.cs :

public ActionResult Index ( )
{
    //...
    return View("View1");
}

[HttpPost]
public ActionResult Index (HttpPostedFileBase file, string selectedOrgName, string selectedCatName)
{
    //...
    ViewBag.orgcatJSON = "some json string"; 
    return View("View2");
}

Views/Example/View1.cshtml :

<h1>View 1</h1>
<!-- specific content here -->

<!-- now include shared content -->
@Html.Partial("SharedContent")

Views/Example/View2.cshtml :

<h1>View 2</h1>
<!-- specific content here -->

<!-- now include shared content -->
@Html.Partial("SharedContent")

<script>
var ogmap = @Html.Raw(ViewBag.orgcatJSON);
$(function() {
      //functionality here
});
</script>

Views/Example/SharedContent.cshtml :

<p>Hello World!</p>

To extend the clearer dependencies point, you could make it even clearer by binding your expected type using the ModelBinder . Then your dependency would be even less hidden and you could replace your usage of the ViewBag with your directly bound json.

For more information about what the ModelBinder is and how it works, I'd suggest you read this post .

If you decide to go this route, change the second Index method and the second View to the following:

Controllers/ExampleController.cs :

[HttpPost]
public ActionResult Index (HttpPostedFileBase file, string selectedOrgName, string selectedCatName)
{
    //...
    //let's pass the json directly to the View and make the dependency 100% clear
    var json = "some json string"; 
    return View("View2", json);
}

Views/Example/View2.cshtml :

@model System.String
<!-- in the above line, we are telling the view what type we expect to be bound by the controller -->
<h1>View 2</h1>
<!-- specific content here -->

<!-- now include shared content -->
@Html.Partial("SharedContent")

<script>
var ogmap = @Html.Raw(model);
$(function() {
      //functionality here
});
</script>

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