LoginSignup
shimauma11
@shimauma11

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

いいね機能の実装(スタイル変更)

いいね機能の実装(スタイル変更)

djangoを使って、Twitterのようなアプリを作成しています。現在は、ajaxを用いたいいね機能の実装に取り組んでいるのですが、「いいね」「いいね取り消し」の切り替えがうまくいきません。

class Like(models.Model):
    tweet = models.ForeignKey(Tweet, related_name="likes", on_delete=models.CASCADE)
    user = models.ForeignKey(
        User, related_name="likes", on_delete=models.CASCADE
    )

    class Meta:
        verbose_name_plural = "いいね"
        constraints = [
            models.UniqueConstraint(fields=["tweet", "user"], name="like_unique"),
        ]

    def __str__(self):
        return f"{self.tweet.content} by {self.user.username}"

def LikeView(request, pk):

    tweet = Tweet.objects.get(pk=pk)
    user = request.user
    Like.objects.get_or_create(user=user, tweet=tweet)

    is_liked = True
    like_count = tweet.likes.count()
    
    ctxt = {
        "is_liked": is_liked,
        "like_count": like_count,
        "tweet_id": pk,
    }

    return JsonResponse(ctxt)


def UnlikeView(request, pk):
    tweet = Tweet.objects.get(pk=pk)
    user = request.user
    like = Like.objects.filter(user=user, tweet=tweet)

    if like.exists():
        like.delete()
    
    is_liked = False
    like_count = tweet.likes.count()

    ctxt = {
        "is_liked": is_liked,
        "like_count": like_count,
        "tweet_id": pk,
    }
    return JsonResponse(ctxt)

    <a href="javascript:void(0)" id="tweet_{{ tweet.id }}" class="like" name="{{ tweet.id }}" type="button" data-is_liked="False" data-url="{% url 'tweets:like' tweet.pk %}">いいね ({{ tweet.like_count }})</a><br>

    <a href="{% url 'tweets:delete' tweet.pk %}">
        <button type="button" class="btn btn-outline-danger">削除</button>
    </a>
    <a class="reverse_button" href="{% url 'tweets:home' %}">
        <button type="button" class="btn btn-primary btn-back">戻る</button>
    </a>
</div>
{% endblock %}

{% block extrajs %}
<script type="text/javascript">

    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    var csrftoken = getCookie('csrftoken');

    function csrfSafeMethod(method) {
        // these HTTP methods do not require CSRF protection
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }
    $.ajaxSetup({
        crossDomain: false, // obviates need for sameOrigin test
        beforeSend: function (xhr, settings) {
            if (!csrfSafeMethod(settings.type)) {
                xhr.setRequestHeader("X-CSRFToken", csrftoken);
            }
        }
    });

    $(".like").on("click", function () {
        console.log("clicked");
        var tweet_id = $(this).attr("name")
        $.ajax({
            type: "POST",
            method: "POST",
            url: $(this).data("url"),
            data: {
                "id": tweet_id
            },
            dataType: "json"
        }).done(function(data){
            
            $("#tweet_"+String(data["tweet_id"])).text("いいね " + "(" + String(data["like_count"] + ")"));

            el = $(".like")

            if (el.data("is_liked") == "False") {
                el.data("is_liked") = "True";
                el.data("url") = "{% url 'tweets:unlike' tweet.pk %}";
            } else {
                el.data("is_liked") = "False";
                el.data("url") = "{% url 'tweets:like' tweet.pk %}";
            }
        })
    });

</script>
{% endblock %}

やってみたこと

上のコードのように、ajax通信が成功したら、まず現在のいいねの数を表示し、その後、data-is_likedの値をTrueに、data_urlの値を「いいね取り消し」のurlに変更することで、「いいね」「いいね取り消し」の切り替えができると考えたのですが、うまくいきません。

解決策を教えていただけると幸いです。

0

1Answer

いいね機能の切り替えが正しく行われない原因は、JavaScriptのコードの中で、変数 el に$(".like") が代入されてて、この要素がクリックされたときに data-is_liked と data-url の値が変更されて、全てのいいねボタンの状態が同期してしまうことかな?

だから、Ajax通信が成功したときに、クリックされた要素 $(this) に対して data-is_liked と data-url の値を変更するように修正すれば、各いいねボタンの状態を正しく反映できるようになる?

実装して確認したわけではないので参考までに

修正後
$(".like").on("click", function () {
  console.log("clicked");
  var el = $(this); // 修正
  var tweet_id = el.attr("name"); // 修正
  $.ajax({
    type: "POST",
    method: "POST",
    url: el.data("url"), // 修正
    data: {
      "id": tweet_id
    },
    dataType: "json"
  }).done(function(data){
    $("#tweet_"+String(data["tweet_id"])).text("いいね " + "(" + String(data["like_count"] + ")"));
    if (el.data("is_liked") == "False") {
      el.data("is_liked", "True"); // 修正
      el.data("url", "{% url 'tweets:unlike' tweet.pk %}"); // 修正
    } else {
      el.data("is_liked", "False"); // 修正
      el.data("url", "{% url 'tweets:like' tweet.pk %}"); // 修正
    }
  })
});
1Like

Comments

  1. @shimauma11

    Questioner
    おかげさまで、解決しました。丁寧なご回答ありがとうございます!

Your answer might help someone💌