skip to Main Content

I am trying to implement a voting system on answers post just like StackOverflow. I am able to do ajax request and everything is stored perfectly as the desired way in the database. But I am facing an issue with my View. In my view, all the answers‘s Html is rendered with one for loop. In this Html element, I am selecting answer by div class called vote with jQuery and doing my ajax call and updating my vote count. But the issue is when I am upvoting one answer, Instead of increasing only its vote count, it increases all the answers vote count at the same time.
I think the mistake in selecting all the div with the vote class name. But I am not able to find a way to select them separately to increase my VoteCount on the selected answers only.
Here is my View Code.

@model AskMe.Models.ViewModel.QuestionDetailViewModel

@{
    ViewBag.Title = "QuestionDetails";
}

<h1>Question Details: </h1>
<h3>@Model.question.Post.Title</h3>
@Html.Raw(Model.question.Post.Content)
<hr />
<h3>Answers:</h3>
<div id="paginationContainer">
    @foreach (var answer in Model.question.Answers)
    {
        <div class="card bg-light m-1">
            <div class="card-body">
                <h5 class="card-title">Answered by: @answer.Post.CreatedBy.UserName</h5>
                @Html.Raw(answer.Post.Content)
            </div>
            <div class="col vote">
                <div>
                    <button data-vote-id="@answer.Post.PostId" class="nav-link thumbs-up" href=""><i class="fa fa-thumbs-up" aria-hidden="true"></i></button>
                </div>
                <div class="Count">
                    @(answer.Post.UpVotes.Count-answer.Post.DownVotes.Count)
                </div>
                <div>
                    <button data-vote-id="@answer.Post.PostId" class="nav-link thumbs-down" href=""><i class="fa fa-thumbs-down" aria-hidden="true"></i></button>
                </div>
            </div>
            @Html.ActionLink("View Comments", "Index", "Comments", new { answerId = answer.PostId }, null) |
        </div>
    }
</div>
@using (Html.BeginForm())
{

    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h3>Contribute your answer: </h3>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

        <div class="form-group">
            @Html.LabelFor(m => m.AnswerContent, new { @class = "col-md-2 control-label" })
            <div class="col-md-10">
                @Html.TextAreaFor(m => m.AnswerContent, new { @class = "form-control" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                @Html.HiddenFor(m => m.UserId)
                @Html.HiddenFor(m => m.QuestionId)
                @Html.HiddenFor(m => m.question)
                <input type="submit" value="Contribute now" class="btn btn-outline-primary" />
            </div>
        </div>
    </div>
}
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval");

    <script type="text/javascript">
        $(document).ready(function () {
            tinyMCE.init({
                mode: "textareas",
            });
            $('#paginationContainer').buzinaPagination({
                itemsOnPage: 3,
                prevnext: true,
                prevText: "Previous",
                nextText: "Next"
            });

            $(".vote").on("click", ".thumbs-up", function () {

                $.ajax({
                    url: "/api/votes/upvote/" + $(this).attr("data-vote-id"),
                    method: "POST",
                    success: function () {
                        var countTxt = $(".Count").text();
                        console.log(countTxt);
                        var count = parseInt(countTxt);
                        $(".Count").text(count + 1);
                        console.log(count);
                    }
                })
            })

            $(".vote").on("click", ".thumbs-down", function () {

                $.ajax({
                    url: "/api/votes/downvote/" + $(this).attr("data-vote-id"),
                    method: "POST",
                    success: function () {
                        var countTxt = $(".Count").text();
                        console.log(countTxt);
                        var count = parseInt(countTxt);
                        $(".Count").text(count - 1);
                        console.log(count);
                    }
                })
            })
        });
    </script>
}

and here is my ViewModel

public class QuestionDetailViewModel
    {
        ApplicationDbContext _context = new ApplicationDbContext();

        public virtual Question question { get; set; }

        [Display(Name = "Add your answer.")]
        public string AnswerContent { get; set; }

        public string UserId { get; set; }

        public int QuestionId { get; set; }

        public int AnswerId { get; set; }

        public int VoteCount { get; set; }
    }

2

Answers


  1. Chosen as BEST ANSWER

    Thanks, @EugenePodskal to point out my mistake and show me the correct direction for the solution. Here is the solution for question.

    $(".vote").on("click", ".thumbs-up", function () {
                    var counter = $(this).closest(".vote").children(".Count");
                    $.ajax({
                        url: "/api/votes/upvote/" + $(this).attr("data-vote-id"),
                        method: "POST",
                        success: function () {
                            var countTxt = counter.text();
                            console.log(countTxt);
                            var count = parseInt(countTxt);
                             counter.text(count + 1);
                            console.log(count);
                        }
                    })
                })
    

    Thanks again @EUgenePodskal for your help and time.


  2. You are selecting and setting all .Count elements as far as I can see in

    var countTxt = $(".Count").text();
    ...
    $(".Count").text(count - 1);
    

    While we should handle only those .Count elements that are related to the current answer.

    It can be done with ancestor + find selector

    var $count = $(this).ancestor(".vote").children(".Count")[0];
    $.ajax({  
        url: "/api/votes/downvote/" + $(this).attr("data-vote-id"),
        method: "POST",
        success: function () {
            var countTxt = $count.text();
            ...
            $count.text(count - 1);
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search