Ajax and Shared Partial Views

Posted On: 9/13/2017 7:47:54 AM

Filed Under: Programming / ASP.NET

I'm working on an MVC project that requires a voting system.  The "panel" where the voting options display are going to show up multiple times on several screens, so my first step was to consolidate this panel into a Partial View with it's own controller.  Updating the Database after a vote has been cast was easy - getting my application to update that individual partial view, however, proved to be much more of a problem.  Please note, I omitted most of the vote-type code for simplicity.  However, in my application you can vote several different ways - which is why it may seem that's what this code is intended for at times.

First, on my display page, I loop through a list of articles and display a voting panel for each:

@foreach (var article in Model.Articles)
    .....MORE CODE GOES HERE....
     <div id="@String.Format("VotePanel{0}", article.Id)">
         @{ Html.RenderAction("ShowVotingPanel", "Vote", article); }

I wrap the partial view in an ID that will identitfy the article later.  This ID is important, as it will be the one we tell Ajax to update at the end.  In my ShowVotingPanel action, I simply assign the article object and some other data to a new VotingPanelViewModel object, and return the VotingPanel partial view with that model.

In my _VotingPanel partial view, I have an anchor tag with an ID that will be used to fire an event based on the article it's attached to:

<a href="#" id="@string.Format("btnVote", Model.Article.Id)">
   <span class="vote-display-class"></span>
    $('#@string.Format("btnVote{0}", Model.Article.Id)').click(function (event) {
        sendAjaxVote(@Model.Article.Id, "cast-vote");

Side note: I'm keeping the Js attached to the voting in it's own file.
Side-side note: I had to use String.Format in the Script because "btnVote" + @Model.Article.Id wasn't working, and this was the quickest way around it.  Please let me know if I can do it any other way.

Now, we use this data in sendAjaxVote:

function sendAjaxVote(aId, voteType) {
    var controllerUrl;
    var votePanelId = "#VotePanel" + aId;

    if (voteType == "cast-vote") {
        controllerUrl = "/Vote/VoteCast";
    } else {
        return false;
    var articleData = { articleId: aId };
        type: "POST",
        url: controllerUrl,
        data: articleData,
        datatype: "html",
        success: function (data) { $(votePanelId).html(data); }


We package the article data to be sent to our controller.  As you can see, on success, we will update the HTML with the data returned by the controller, which in this case is our partial view.  So, in the controller:

public ActionResult VoteCast(int articleId)
    if (_voteFunctions.CastVote(articleId))
        return Content("An error occured. Please reload page.");
    Article article = _articleRepository.GetEntityById(articleId);
    return PartialView("_VotingPanel", CreateVotingPanelViewModel(article));

_voteFunctions is simply a reference to an object that exists in our service layer, and handles adding/removing/changing votes in the database.  The CreateVotingPanelViewModel is a local function that creates a ViewModel object for the Voting panel.  Finally, the _articleRepository is exactly what it sounds like.  After our logic is performed, we return the proper Partial View with it's corresponding View Model, and VIOLA!

Please comment corrections, or any clarifications below.