Eric Freeman
Eric Freeman

Reputation: 61

Reloading Partial View with JQuery

I have a page with a video at the top and a list of videos you can choose from. Currently, clicking a link in the video list will reload the entire page. I need it to only refresh the partial view I have containing the video at the top of the page.

I saw several posts here on SO showing how to reload partial views with JQuery, but couldn't get it to work correctly in my situation. I'm unsure how to pass the correct id of the video along.

Controller:

    public ActionResult Videos(int topVideo = 0)
    {
        VideosModel model = new VideosModel();
        model.Videos = StatsVideoService.GetEntityList(new Lookup(TableStatsVideo.IsDeleted, false)).OrderByDescending(x => x.DateCreated).ToList();

        if (topVideo == 0)
            model.TopVideo = model.Videos.First();
        else
        {
            model.TopVideo = model.Videos.Where(x => x.StatsVideoId == topVideo).FirstOrDefault();
            if (model.TopVideo == null)
                model.TopVideo = model.Videos.First();
        }

        return View(model);
    }

View:

@model Project.Models.VideosModel

<section class="videos">
    <div id="top_video">
        @{Html.RenderPartial("StatsVideo", Model.TopVideo);}
    </div>

    <ul>
        @foreach (var item in Model.Videos)
        {
            <li>
                <div class="videoList">
                    <a href ="@Url.Action("Videos", "Home", new { topVideo = item.StatsVideoId })">
                        <img src="@Url.Content("~/Content/img/video-ph.png")" />
                    </a>
                    <p class="videoTitle">@item.Title</p>
                </div>
            </li>
        }
    </ul>
</section>

If there's any more information needed, please let me know.

Upvotes: 2

Views: 11891

Answers (3)

Eric Freeman
Eric Freeman

Reputation: 61

After several hours of bashing my head against the wall, I got it to work! Just as a reference to anyone else in the future who's viewing this article, here's how I got it to work:

I set the onclick of the link to point to a javascript method, passing in the id of the video as a parameter:

    @foreach (var item in Model.Videos)
    {
        <li>
            <div class="videoList">
                <a href ="#" onclick="updateTopVideo(@item.StatsVideoId)">
                    <img src="@Url.Content("~/Content/img/video-ph.png")" />
                </a>
                <p class="videoTitle">@item.Title</p>
            </div>
        </li>
    }

And then I included this script in the view at the bottom:

<script>
    var updateTopVideo = function (itemId) {

        var url = '@Url.Content("~/Home/StatsVideo/")';
        url = url + itemId;
        $.get(url, "", callBack, "html");
    };

    var callBack = function (response) {
        $('#top_video').html(response);
    };
</script>

Finally, I added a method to my controller that would return the partial view needed for the video at the top of the screen:

    public ActionResult StatsVideo(int Id)
    {
        IStatsVideo vid = StatsVideoService.GetEntity(new Lookup(TableStatsVideo.StatsVideoId, Id));
        if (vid == null)
            vid = StatsVideoService.GetEntityList(new Lookup(TableStatsVideo.IsDeleted, false)).OrderByDescending(x => x.DateCreated).FirstOrDefault();

        return PartialView(vid);
    }

This code should be fairly easy to understand. Basically, the onclick calls the first javascript method, which then calls the controller. The controller builds the partial view and returns it. The first javascript method passes it to the second javascript method which sets the html of the div "top_video" to be the returned partial view.

If anything doesn't make sense, or anyone's having trouble with this in the future, let me know and I'll do my best to offer some help.

Upvotes: 3

John Koerner
John Koerner

Reputation: 38087

You can remove the around the image and just store the url generated by the Url.Action in a data-href attribute.

Then you can use the jquery load method to load the data:

$(".videolist>img").click(function () {
    $("#content").load($(this).data("href"));
});

I created a fiddle that loads content dynamically here, so you can play with it if you want: http://jsfiddle.net/bTsLV/1/

Upvotes: 1

David L
David L

Reputation: 33873

I think there may be several confusing and inconsistent elements here.

First, you are returning a full view instead of a partial view. This reloads all containing elements, not just the part that is relevant to your partial view.

Second, you are using Url.Action, which only generates the url. I would recommend using Ajax.ActionLink, which allows you to do fully ajax calls, refreshing the content of your partial div and updating a target div element.

instead of:

<div class="videoList">
                <a href ="@Url.Action("Videos", "Home", new { topVideo = item.StatsVideoId })">
                    <img src="@Url.Content("~/Content/img/video-ph.png")" />
                </a>
                <p class="videoTitle">@item.Title</p>
            </div>

try the more modern solution

<div class="videoList">
@Ajax.ActionLink(
"Videos", 
"Home", 
"new { topVideo = item.StatsVideoId }, 
new AjaxOptions {  
    HttpMethod = "GET", 
    OnSuccess = "handleSuccess" 
}
)
</div>

This way you can be very specific on what you want each link to do, and you can pass along multiple parameters as well as define a callback function. You can also use "UpdateTargetId" in your ajax options to load your newly refreshed partial view into a DOM element.

Upvotes: 1

Related Questions