喜欢/不喜欢功能

like/dislike at same time

I have this ajax function of liking and disliking a comment but with this function, I can like and dislike at the same time. for example When I like the comment it is liking it and if after that I dislike it does that too without removing my like.

Here is the code for like (upvote) and dislike (downvote)

up votes

$(".tup").click(function (e) {

    e.preventDefault();
    var reviewId = $(this).data('id');

    $.ajax({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            },
            url: document.location.origin + '/review/' + reviewId + '/upvote',
            type: 'POST',
            data: {
                review_id: reviewId
            },
            dataType: 'json'
        })
        .done(function (data) {

            if (data == true) {
                $('.tup[data-id=' + reviewId + '] .vn').text(function (i, oldVal)
                 {
                    return parseInt(oldVal, 10) + 1;
                });
            } else {
                snackybar.timer("Already Voted", 3000);
            }

        })
        .fail(function (jqXHR, textStatus) {
            console.log("Request failed: " + textStatus);
        });
});

// down votes

$(".tdown").click(function (e) {
    e.preventDefault();
    var reviewId = $(this).data('id');

    $.ajax({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            },
            url: document.location.origin + '/review/' + reviewId + '/downvote',
            type: 'POST',
            data: {
                review_id: reviewId
            },
            dataType: 'json'
        })
        .done(function (data) {
            if (data == true) {
                $('.tdown[data-id=' + reviewId + '] .vn').text(function (i, oldVal) {
                    return parseInt(oldVal, 10)  + 1;
                });
            } else {
                snackybar.timer("Already Voted", 3000);
            }
        })
        .fail(function (jqXHR, textStatus) {
            console.log("Request failed: " + textStatus);
        });
});

And this is the controller's code

 public function upvote($id) {
    if(!UpDownVote::where('review_id',$id)->where('upvote',1)->first()) {
        Review::findOrFail($id)->increment('upvote');
        UpDownVote::create([
            'user_id' => Auth::user()->id,
            'review_id' => $id,
            'upvote' => 1
        ]);
        return 'true';
    } else {
        return 'false';
    }
}

public function downvote($id) {
    if(!UpDownVote::where('review_id',$id)->where('downvote',1)->first()) {
        Review::findOrFail($id)->increment('downvote');
        UpDownVote::create([
            'user_id' => Auth::user()->id,
            'review_id' => $id,
            'downvote' => 1
        ]);
        return 'true';
    } else {
        return 'false';
    }
}

The issue is that your Ajax calls are asynchronous; thus, when clicking on tup button and then the tdown one, perhas the treatment have not been done already when you click on the second button.

You can disabled the possibility of clicking when you are waiting for the server response.

var isClicking = false;
$(".tup").click(function (e) {
if(isClicking){
   return;
}
isClicking = true;
e.preventDefault();
var reviewId = $(this).data('id');

$.ajax({
        headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
        },
        url: document.location.origin + '/review/' + reviewId + '/upvote',
        type: 'POST',
        data: {
            review_id: reviewId
        },
        dataType: 'json'
    })
    .done(function (data) {

        if (data == true) {
            $('.tup[data-id=' + reviewId + '] .vn').text(function (i, oldVal)
             {
                return parseInt(oldVal, 10) + 1;
            });
        } else {
            snackybar.timer("Already Voted", 3000);
        }

    })
    .fail(function (jqXHR, textStatus) {
        console.log("Request failed: " + textStatus);
    }).always(function(){
     isClicking=false;
  });
});

// down votes




 $(".tdown").click(function (e) {
e.preventDefault();
if(isClicking){
   return;
}
isClicking = true;
var reviewId = $(this).data('id');

$.ajax({
        headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
        },
        url: document.location.origin + '/review/' + reviewId + '/downvote',
        type: 'POST',
        data: {
            review_id: reviewId
        },
        dataType: 'json'
    })
    .done(function (data) {
        if (data == true) {
            $('.tdown[data-id=' + reviewId + '] .vn').text(function (i, oldVal) {
                return parseInt(oldVal, 10)  + 1;
            });
        } else {
            snackybar.timer("Already Voted", 3000);
        }
    })
    .fail(function (jqXHR, textStatus) {
        console.log("Request failed: " + textStatus);
    }).always(function(){
     isClicking=false;
  });
});