Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement logic for adding likes without a separate HTML request?

I have implemented the logic of adding likes to articles:

html

<a href="/article/{{ $article->id }}?type=heart" class="comments-sub-header__item like-button {{ $article->hasLikedToday('heart') ? 'active' : '' }}">
    <div class="comments-sub-header__item-icon-count"> {{ $article->getLikeHeartTotal() }} </div>
</a>

<a href="/article/{{ $article->id }}?type=finger" class="comments-sub-header__item like-button {{ $article->hasLikedToday('finger') ? 'active' : '' }}">
    <div class="comments-sub-header__item-icon-count"> {{ $article->getLikeFingerTotal() }} </div>
</a>

php

model

public function hasLikedToday(string $type)
{
    $articleLikesJson = Cookie::get('article_likes', '{}');

    $articleLikes = json_decode($articleLikesJson, true);

    if (!array_key_exists($this->id, $articleLikes)) {
        return false;
    }

    if (!array_key_exists($type, $articleLikes[$this->id])) {
        return false;
    }

    $likeDatetime = Carbon::createFromFormat('Y-m-d H:i:s', $articleLikes[$this->id][$type]);

    return !$likeDatetime->addDay()->lt(now());
}

public function setLikeCookie(string $type)
{
    $articleLikesJson = Cookie::get('article_likes', '[]');

    $articleLikes = json_decode($articleLikesJson, true);

    $articleLikes[$this->id][$type] = now()->format('Y-m-d H:i:s');

    $articleLikesJson = json_encode($articleLikes);

    return cookie()->forever('article_likes', $articleLikesJson);
}

controller

public function postLike($id, Request $request)
{
    $article = Article::find($id);

    if (!$article) {
        return abort(404);
    }

    $type = $request->input('type');

    if ($article->hasLikedToday($type)) {
        return response()
            ->json(
                [
                    'message' => 'You have already liked the Article ' . $article->id . ' with ' . $type . '.',
                ]
            );
    }

    $cookie = $article->setLikeCookie($type);

    $article->increment("like_{$type}");

    return response()
        ->json(
            [
                'message' => 'Liked the Article ' . $article->id . ' with ' . $type . '.',
                'cookie_json' => $cookie->getValue(),
            ]
        )
        ->withCookie($cookie);
}

js

$(function() {
  $.ajaxSetup({
    headers: {
      'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'),
    },
  });

  $('.like-button').on('click', function(event) {
    event.preventDefault();
    var targetElement=$(this);

    let href = $(this).attr('href');

    $.ajax({
      url: href,
      type: 'POST',
      success: function() {
        if (targetElement.hasClass('active')) { 
          return false;
        }

        else {
          var counter = targetElement.find('.comments-sub-header__item-icon-count');
          var current = parseInt(counter.html());

          counter .html(current + 1)
      
            targetElement.addClass('active');
        }
     },
    });
  });
});

Now it turns out that both types of likes have a separate html page like /article/11?type=heart and /article/11?type=finger

Because of these links to the page, Google software swears, and gives such an error

the server returned a 405 method not allowed

Can I somehow keep all this functionality in a simple way, but make it so that the like request is not a POST and does not have a link so as not to receive such an error?

like image 404
Hector Avatar asked Sep 02 '25 13:09

Hector


2 Answers

If you don't need <a> tag then you change that to span or button and then use data-attr for setting value of $article->id & type. Then, use this data-attr to fetch value in ajax and pass it your server .

Changes you can do in your code :

HTML :

<!--added span tag and use data-attr-->
<span data-id="{{ $article->id }}" data-type="heart" class="comments-sub-header__item like-button {{ $article->hasLikedToday('heart') ? 'active' : '' }}">
    <div class="comments-sub-header__item-icon-count"> {{ $article->getLikeHeartTotal() }} </div>
</span>

<span data-id="{{ $article->id }}"  data-type="finger" class="comments-sub-header__item like-button {{ $article->hasLikedToday('finger') ? 'active' : '' }}">
    <div class="comments-sub-header__item-icon-count"> {{ $article->getLikeFingerTotal() }} </div>
</span>

AJAX:

  $('.like-button').on('click', function(event) {
    var targetElement=$(this);

    let article_id = targetElement.data('id');
    let type = targetElement.data('type');
    let href = `/article/${article_id}?type=${type}`
    //your ajax call change type:"POST" to type:"GET"

  });

Code Demo :

$('.like-button').on('click', function(event) {
  var targetElement = $(this);

  let article_id = targetElement.data('id');
  let type = targetElement.data('type');
  let href = `/article/${article_id}?type=${type}`
  console.log(href)
  //..your ajax call change type:"POST" to type:"GET"
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span data-id="1" data-type="heart" class="comments-sub-header__item like-button active">
        <div class="comments-sub-header__item-icon-count"> 1</div>
</span>

<span data-id="2" data-type="finger" class="comments-sub-header__item like-button active">
        <div class="comments-sub-header__item-icon-count"> 2 </div>
</span>
like image 79
Swati Avatar answered Sep 05 '25 04:09

Swati


Basically, you need to make sure that you decide whether you want your request to be GET and POST as well as making sure that the routes are set correctly. If you want to have a GET route, then you will need something like

Route::get('/article/{id}', function (string $id) {
    $type = $request->type; //getting the type
    //your code here
    return 'success';
});

or, if you want a post, you can have something like

Route::post('/article/{id}', function (string $id) {
    $type = $request->type; //getting the type
    //your code here
    return 'success';
});

Of course, you will need to make sure that your AJAX request has type: 'POST', if it's a POST request and type: 'GET',, if it's a GET request, respectively.

like image 44
Lajos Arpad Avatar answered Sep 05 '25 03:09

Lajos Arpad