xslibx
xslibx

Reputation: 4349

How do I handle an Ajax Response in my Laravel Controller?

I'm creating a social network site using Laravel. I'm using ajax so users can post comments on a dynamic amount of posts.

My problem is I do not know how to respond to the ajax in my controller. My console shows that ajax returns the entire page. This results in an incorrect display of the new comments being posted until the page is reloaded. So I added an if statement to handle ajax but I don't know how to handle it.

The VIEW for my comments looks like this.

<div class="comment-box-container ajax-refresh">
// COMMENTS ARE DISPLAYED HERE
  <div class="comment-box">
    @if ($type->comments)
      @foreach ($type->comments as $comment)

        <div class="user-comment-box">

          <div class="user-comment">
            <p class="comment">
<!-- starts off with users name in blue followed by their comment-->
              <span class="tag-user"><a href="{{ route('profile', $comment->owner->id) }}">{{ $comment->owner->first_name }}&nbsp;{{ $comment->owner->last_name }}</a>&nbsp;</span>{{ $comment->body }}
            </p>
<!-- Show when the user posted comments-->
          <div class="com-details">
            <div class="com-time-container">
              &nbsp;{{ $comment->created_at->diffForHumans() }} ·
            </div>
          </div>

        </div><!--user-comment end-->
      </div><!--user-comment-box end-->
    @endforeach
  @endif
// USER TYPES COMMENT HERE
<!--type box-->
  <div class="type-comment">
    <div class="type-box">
    {{ Form::open(['data-remote', 'route' => ['commentPost', $id], 'class' => 'comments_create-form']) }}
        {{ Form::hidden('user_id', $currentUser->id) }}
        {{ Form::hidden($idType, $id) }}
        {{--{{ Form::hidden('user_id', $currentUser->id) }}--}}
        {{ Form::textarea('body', null, ['class' =>'type-box d-light-solid-bg', 'placeholder' => 'Write a comment...', 'rows' => '1']) }}
    {{ Form::close() }}
    </div><!--type-box end-->
  </div><!--type-comment-->

</div><!--comment-box end-->

The user submit the form for the comment type box by pressing the "enter/return" key. Here is the JS for that

<script>
    $(document).on('keydown', '.comments_create-form', function(e) {
        if (e.keyCode == 13) {
            e.preventDefault();
            $(this).submit();
        }
    });
</script>

And my Ajax looks like this:

(function(){

$(document).on('submit', 'form[data-remote]', function(e){
    e.preventDefault();
    var form = $(this)
    var target = form.closest('div.ajax-refresh');
    var method = form.find('input[name="_method"]').val() || 'POST';
    var url = form.prop('action');

    $.ajax({
        type: method,
        url: url,
        data: form.serialize(),
        success: function(data) {
            var tmp = $('<div>');
            tmp.html(data);
            target.html( tmp.find('.ajax-refresh').html() );
            target.find('.type-box').html( tmp.find('.type-box').html() );
            tmp.destroy();
            }
    });
});
})();

The comments is processed in the CommentsController . My controller looks like this:

Route

Route::post('post/{id}/comment', ['as' => 'commentPost', 'uses' => 'CommentsController@postComment']);

Controller

public function postComment()
 {
     extract(Input::only('user_id', 'resource_id', 'body'));
     $this->execute(new PostCommentCommand($user_id, $resource_id, $body));
     if(Request::ajax()){
        // NOT SURE WHAT TO PUT HERE???
     }
     return Redirect::back();
 }

I'm using a Commandbus . PostCommentCommand is a Data Transfer Object that ultimately get processed through the PostCommentCommandHandler using the handle() method:

public function handle($command)
{
    $comment = $this->postRepository->leaveComment($command->user_id, $command->resource_id, $command->body);

    return $comment;

}

postRepository->leaveComment() Looks like this:

public function leaveComment($user_id, $resource_id, $body)
{
    $comment = Comment::leavePostComment($resource_id, $body);

    User::findOrFail($user_id)->comments()->save($comment);

    return $comment;
}

I'm not sure how to make this work in my controller. I know I need to determine if I'm using ajax if(Request::ajax()){} but I do not know what to do after that.

My main objective with this is that I'm trying to make a comment system similar to facebook. where users can comments on any post on any page without the page reloading. I'm hoping to use this same ajax system for a 'Like system' so users can like photos and comments without the page reloading aswell.

Does anyone have any ideas, or solutions for this? I'm new to Laravel and even newer to Ajax and JavaScript. A detailed description would be very appreciated. Thanks!

Upvotes: 0

Views: 3663

Answers (1)

Bogdan
Bogdan

Reputation: 44526

Based on your current code here's how I would go about finishing up the ajax request:

1. Create a comment.blade.php partial view for an individual comment:

<div class="user-comment-box">
    <div class="user-comment">
        <p class="comment">
            <span class="tag-user">
                <a href="{{ route('profile', $comment->owner->id) }}">
                    {{ $comment->owner->first_name }} {{ $comment->owner->last_name }}
                </a>
            </span>
            {{ $comment->body }}
        </p>
        <div class="com-details">
            <div class="com-time-container">
                &nbsp;{{ $comment->created_at->diffForHumans() }} ·
            </div>
        </div>
    </div>
</div>

2. Include the new comment view within your comment foreach loop:

<div class="comment-box-container ajax-refresh">
    <div class="comment-box">
        @if ($type->comments)
            @foreach ($type->comments as $comment)
                @include('comment')
            @endforeach
        @endif

        <div class="type-comment">
            <div class="type-box">
                {{ Form::open(['data-remote', 'route' => ['commentPost', $id], 'class' => 'comments_create-form']) }}
                    {{ Form::hidden('user_id', $currentUser->id) }}
                    {{ Form::hidden($idType, $id) }}
                    {{--{{ Form::hidden('user_id', $currentUser->id) }}--}}
                    {{ Form::textarea('body', null, ['class' =>'type-box d-light-solid-bg', 'placeholder' => 'Write a comment...', 'rows' => '1']) }}
                {{ Form::close() }}
            </div>
        </div>
    </div>
</div>

3. Now when handling the ajax request for your postComment method, you should return the commend.blade.php view populated with the details of the new comment like so:

public function postComment()
{
    extract(Input::only('user_id', 'resource_id', 'body'));

    // get the new comment model
    // (also the method here is "dispatch" not "execute")
    $comment = $this->dispatch(new PostCommentCommand($user_id, $resource_id, $body));

    if (Request::ajax())
    {
        // return the comment view you created earlier
        // passign the new comment model to it
        return view('comment', compact('comment'));
    }

    return Redirect::back();
 }

4. In your JavaScript AJAX success callback, you're now getting a HTML response with the new comment. You just need to insert that at the end of you comments list, just before the form:

$.ajax({
    type: method,
    url: url,
    data: form.serialize(),
    success: function(response)
    {
        form.closest('.type-comment').before(response);
    }
});

That's about it.


The same logic can be applied to any other asynchronous action, with small differences according to each case. For example to "like" a comment, you'd send an AJAX request, and from the server you could reply with a JSON response that specifies if the action was successful or not. The Laravel part would look something like this:

$liked = like_comment($id); // this is generic
return response()->json(['success' => $liked]);

And on the client side, you'd have something like this:

success: function(response)
{
    if (response.success)
    {
        // update the necessary parts of the page
    }
}

Upvotes: 1

Related Questions