3

With old ASP.NET we could create User controls(.ascx) easily, in fact many controls were/are fully independent from the current View. I wonder if the same is possible with MVC?

I need to display simple list with users, problem is - this list should be displayed in more then one places on my site. While I can simply modify my views models, and add model of the "widget" to them, I would like to avoid this. Preferably I would like my users list to require only the following:

@Html.Partial("Link/To/My/List")

to be included in other View - list's model would have to be populated some other way. I thought to use AJAX inside my partial but this seems like a bad idea. Is there any other way around it or is it simply a bad idea that breaks MVC assumptions?

Praveen Reddy
  • 7,295
  • 2
  • 21
  • 43
user2384366
  • 1,034
  • 2
  • 12
  • 28

2 Answers2

4

You can use the RenderAction method to render a Partial view. The partial view can be associated with a Model that is different from the calling page's Model

Calling the action method from the View

@{Html.RenderAction("SomeAction", "SomeController");} 

Action method returns the partial view

public ActionResult SomeAction()
        {
            //Construct SomeModel here..  
            return PartialView("SomeView", SomeModel);
        }
Praveen Reddy
  • 7,295
  • 2
  • 21
  • 43
  • 3
    And if you don't want someone to accidentally call this partial view outside a view (directly from a web browser) you can add the [`ChildActionOnlyAttribute`](http://msdn.microsoft.com/en-us/library/system.web.mvc.childactiononlyattribute(v=vs.118).aspx) to the method. – Erik Philips Jun 03 '14 at 22:30
  • 1
    @ErikPhilips: This works great, however - is there a way to include js scripts, as well? For example - assuming we have a "widget" with drop down box, when option is selected widget should be reloaded via ajax. While this is easy to do it requires us to include scripts in the main view that use our widget - is there a way to include the scripts along with the partial view? – user2384366 Jun 04 '14 at 10:16
  • Not out of the box. Take a look at [How to render a Section in a Partial View in MVC3?](http://stackoverflow.com/questions/13764936/how-to-render-a-section-in-a-partial-view-in-mvc3/13765578#13765578) – Erik Philips Jun 04 '14 at 14:54
  • @ErikPhilips: Thanks again - I think this will do the trick. Why guys from MS have to make such a weird design decisions (trying to protect developers from themselves I guess?) is beyond me. – user2384366 Jun 05 '14 at 05:11
  • My personal opinion is that it's quite the opposite (at least in this case). It just came down to [Why doesn't feature X exist?](http://blogs.msdn.com/b/ericlippert/archive/2009/06/22/why-doesn-t-c-implement-top-level-methods.aspx). – Erik Philips Jun 05 '14 at 13:53
  • @ErikPhilips i am trying to do the same thing but, getting an exception : _Additional information: No route in the route table matches the supplied values_ – Protect Life Save Forests Sep 16 '15 at 05:32
  • do we have to define separate route for this (independent) partial view? – Protect Life Save Forests Sep 16 '15 at 05:34
1

You can write partial views that are encapsulated "widgets" by embedding a script block inside the partial view. Wrapping a script block inside a div is one clean way to wrap the markup and the initialization script together in a partial view widget. For example, I might have a partial view named "_WidgetPartial" that I use throughout my site. If I place in two places on my master page it should just work and I prefer not to have to write logic in my master page to initialize the widget.

You might want to write the widget as a jQuery plugin of some sort and then the script block becomes a simple one liner to initialize it. The partial view looks something like...

<div id="widgetWrapper">

    <ul class="widget">
    </ul>

    <script>
        $(document).ready(function() {
            $("ul.widget").widget(...);
        });
    </script>
</div>

If you will never use it more than once in a page, its simple, otherwise, wrap the code so it doesn't execute twice. See below. For the sake of Stack Overflow snippets I simulate it by repeating the partial view twice in the code snippet to represent including a partial view widget twice in a master page.

My master page might look like:

<div id="left-nav">
   @Html.Partial("_WidgetPartial")           
</div>

<div id="body">
</div>

<div id="right-nav">
   @Html.Partial("_WidgetPartial")
</div>

Example:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<!-- Self-contained partial view containing widget -->

<div id="widgetDiv" class="panel panel-default">

    <div class="panel-heading">Event Dates</div>
    <div class="panel panel-group">
       <ul class="widget">
         <!-- These will load dynamically -->
       </ul>
    </div>

    <script>
        $(document).ready(function() {

            // Run this once only in case widget is on page more than once
            if(typeof $widget == 'undefined') {
                $widget = $("ul.widget"); // could be more than one
                // mock data to simulate an ajax call
                var data = [
                   {Description: "March", StartDate: "03/01/2015"},
                   {Description: "April", StartDate: "04/01/2015"},
                   {Description: "May", StartDate: "05/01/2015"}
                ];

                $.each($widget, function(w, widget) {
                    // might be an $.ajax call
                    $.each(data, function(i, row) {
                        $(widget).append("<li><a href='/Widget/Search?startDate=" + row.StartDate + "'>" + row.Description + "</a></li>");
                    });
                });
            }
        });
    </script>
</div>
<!-- End of widget / partial view -->



<!-- Second copy of above for sake of example snippet -->
<!-- No need to read further -->









<!-- Self-contained partial view containing widget -->

<div id="widgetDiv" class="panel panel-default">

    <div class="panel-heading">Event Dates</div>
    <div class="panel panel-group">
       <ul class="tinylist nav nav-sidebar widget">
         <!-- These will load dynamically -->
       </ul>
    </div>

    <script>
        $(document).ready(function() {

            // Run this once only in case widget is on page more than once
            if(typeof $widget == 'undefined') {
                $widget = $("ul.widget"); // could be more than one
                // mock data to simulate an ajax call
                var data = [
                   {Description: "March", StartDate: "03/01/2015"},
                   {Description: "April", StartDate: "04/01/2015"},
                   {Description: "May", StartDate: "05/01/2015"}
                ];

                $.each($widget, function(w, widget) {
                    // might be an $.ajax call
                    $.each(data, function(i, row) {
                        $(widget).append("<li><a href='/Widget/Search?startDate=" + row.StartDate + "'>" + row.Description + "</a></li>");
                    });
                });
            }
        });
    </script>
</div>
<!-- End of widget / partial view -->
codenheim
  • 20,467
  • 1
  • 59
  • 80