4

Hey everyone i'm having an issue editing comments with ajax in laravel 5.4

This works in a modal "press edit and modal opens" so the problem is when y click on edit "editar" i get the 500 (Internal Server Error)

First of all i will show you my js code:

$(document).ready(function(){

var commentId = 0;
    var divcomment = null;

    $('.edit-comment').click(function(event){
      event.preventDefault();
      var divcomment = this.parentNode.parentNode;
      commentId = event.target.parentNode.parentNode.dataset['commentid'];
      var commentBody = $(divcomment).find('#display-comment').text();
      $('#comment-body').val(commentBody);
      $('#edit-comment').modal();
    });

    $('#modal-save').click(function(){
        $.ajax({
            method: 'PUT',
            url: urlEdit,
            data: {comment: $('#comment-body').val(), commentId: commentId, _token: token}
        })
        .done(function (msg){
            $(divcomment).text(msg['new_comment']);
            $('#edit-comment').modal('hide');
        });
    });

});

My comments controller, update function:

    public function update(Request $request)
{

    $this->validate($request, [
        'comment' => 'required'
    ]);
    $comment = Comment::find($request['commentId']);
    if (Auth::user() != $comment->user) {
        return redirect()->back();
    }
    $comment->comment = $request['comment'];
    $comment->update();
    return response()->json(['new_comment' => $comment->comment], 200);

}

I make a var for url: urlEdit, on my view so here's my view:

<article class="row">
                        <div class="col-md-3 col-sm-3 hidden-xs">
                          <figure class="thumbnail">
                            <img class="img-responsive" src="/uploads/avatars/{{ $comment->user->profilepic  }}" />
                            <figcaption class="text-center">{{ $comment->user->name }}</figcaption>
                          </figure>
                        </div>
                        <div class="col-md-8 col-sm-8">
                          <div class="panel panel-default arrow left">
                            <div class="panel-body">
                              <header class="text-left">
                                <div class="comment-user"><i class="fa fa-user"></i> {{ $comment->user->name }}</div>
                                <time class="comment-date" datetime="{{ $comment->created_at->diffForHumans() }}"><i class="fa fa-clock-o"></i> {{ $comment->created_at->diffForHumans() }}</time>
                              </header>
                              <div id="comment-post" data-commentid="{{ $comment->id }}">
                                  <p id="display-comment">{{ $comment->comment }}</p>
                              </div>
                            </div>

                            <div class="panel-footer list-inline comment-footer">
                              @if(Auth::guest())

                              No puedes responder ningún comentario si no has ingresado.

                              @else

                              @if(Auth::user() == $comment->user)
                                <a href="#" data-toggle="modal" data-target="edit-comment" class="edit-comment">Editar</a> <a href="#" data-toggle="modal" data-target="delete-comment" class="delete-comment">Eliminar</a>
                              @endif

                              @if(Auth::user() != $comment->user)
                                <a href="#">Responder</a>        
                              @endif

                              @endif
                            </div>

                          </div>
                        </div>
                      </article>

This is the modal:

<div class="modal fade" id="edit-comment" tabindex="-1" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title" style="color:#000;">Editar Comentario</h4>
      </div>
      <div class="modal-body">
        <form>
          <div class="form-group">
            <label for="comment">Editar comentario</label>
            <textarea class="form-control" name="comment" id="comment"></textarea>
          </div>
        </form>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn-comment-dismiss btn-comment-modal" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span> Cerrar</button>
        <button type="button" class="btn-comment-edit btn-comment-modal" id="modal-save"><span class="glyphicon glyphicon-ok"></span> Editar</button>
      </div>
    </div>
  </div>
</div>

of course that is inside of a foreach loop.

I made 2 vars on my view:

    <script>
    $(document).ready(function(){
     var token = '{{ Session::token() }}';
     var urlEdit = '{{ url('comments/update') }}';
    });
    </script>

And finally a screenshot:
Screenshot

Thank you in advance.

Juan Rincón
  • 307
  • 5
  • 15
  • click on link and see what is error – kunal Jun 03 '17 at 07:27
  • Thank you for answer, this is what i get: at HandleExceptions->handleError(8, 'Trying to get property of non-object', '/Users/juanr/Sites/devmedia/app/Http/Controllers/CommentsController.php', 84, array('request' => object(Request), 'id' => 'update', 'comment' => null)) this is the line 84 if (Auth::user() != $comment->user) { i was suspecting about the id but now i know that im passing the data as null.. but im calling the id on my json – Juan Rincón Jun 03 '17 at 07:34
  • 1
    @JuanRincón An error does no help in a comment; [edit] your question instead. – Daedalus Jun 03 '17 at 07:37
  • looking the screenshot in error line: http://localhost:8000/comments/update the error is there.. it should be http://localhost:8000/comments/update/4 because that comment id is 4. but is not getting the id – Juan Rincón Jun 03 '17 at 07:39
  • change the method : "put" to type: "post" – kunal Jun 03 '17 at 07:40
  • @JuanRincón Apart from what Kunal said, if you are using a resource controller, you need to add another property to your data object with the name `_method` and the value `PUT`. See [the docs](https://laravel.com/docs/5.4/routing#form-method-spoofing) for more information. – Daedalus Jun 03 '17 at 07:44
  • @JuanRincón Please give your full comments method from the controller. – Daedalus Jun 03 '17 at 07:50
  • @Daedalus Route::put('comments/{id}', ['uses' => 'CommentsController@update', 'as' => 'comments.update']); – Juan Rincón Jun 03 '17 at 07:52
  • @Daedalus i have this one too but i'm not using it, this route is for redirect to a view where i can edit the comment with the comment id Route::get('comments/{id}/edit', ['uses' => 'CommentsController@edit', 'as' => 'comments.edit']); – Juan Rincón Jun 03 '17 at 07:53
  • @Daedalus public function update(Request $request, $id) { $this->validate($request, [ 'comment' => 'required' ]); $comment = Comment::find($request['commentId']); if (Auth::user() != $comment->user) { return redirect()->back(); } $comment->comment = $request['comment']; $comment->update(); return response()->json(['new_comment' => $comment->comment], 200); } – Juan Rincón Jun 03 '17 at 07:54
  • @JuanRincón You aren't passing the comment's id into the global url function, therefore it has no id to access. – Daedalus Jun 03 '17 at 07:54
  • @JuanRincón If you aren't going to edit your question, I am not going to help further. It is very difficult to parse code in a comment. This is the last time I will be asking. – Daedalus Jun 03 '17 at 07:55
  • i'm sorry, what do you need, i will be most clean possible – Juan Rincón Jun 03 '17 at 08:01
  • @JuanRincón https://stackoverflow.com/questions/44341482/500-internal-server-error-ajax-and-laravel#comment75686127_44341482 – Daedalus Jun 03 '17 at 08:02
  • my english is not so good, what exactly do you want me to edit in my question? – Juan Rincón Jun 03 '17 at 08:05
  • @JuanRincón Edit in your code into the question. There is an edit link at the bottom of the question. Here is another: [edit]. Do not post updates that contain error messages, or code, in comments. – Daedalus Jun 03 '17 at 08:06
  • @JuanRincón In any case; your problem is your url. You are not passing the comment-id in the url, thus it will fail. Just do this: `url: urlEdit + '/' + commentId,` in your ajax config. It is almost 2am; I can't debug this further tonight. – Daedalus Jun 03 '17 at 08:13
  • @Daedalus now i'm getting this error: `POST http://localhost:8000/comments/update/undefined 404 (Not Found)` – Juan Rincón Jun 03 '17 at 08:20
  • @Daedalus hey thank you for take the time, have a good night – Juan Rincón Jun 03 '17 at 08:22
  • @JuanRincón Before I go to bed; that would mean your `commentId` variable does not exist at the time of your ajax request. That is why it is failing to work when you try to get it from the request class php wise. – Daedalus Jun 03 '17 at 08:23
  • I thought about that too but I'll see how I do it, I'm not good with js but will try, 4:27 am here – Juan Rincón Jun 03 '17 at 08:27

3 Answers3

1

There are several problems with your code. Firstly; your variable commentId does not exist at the time of your ajax request, thus is it is not present when the controller is called on the php-side of things. Since you are using jQuery, this can be easily fixed.

The main difference between your js and the js below, is that I have replaced your

commentId = event.target.parentNode.parentNode.dataset['commentid'];

with

commentId = $("#comment-post", event.target.parentNode.parentNode).data('commentid');

since you are using jQuery.

The above line is equivalent to $(event.target.parentNode.parentNode).find('#comment-post').data('commentId');

Of note, I have commented out the ajax request; the main issue was that commentId did not exist; with the above change, it now does.

$(document).ready(function() {

  var commentId = 0;
  var divcomment = null;

  $('.edit-comment').click(function(event) {
    event.preventDefault();
    var divcomment = this.parentNode.parentNode;
    commentId = $("#comment-post", event.target.parentNode.parentNode).data('commentid');
    var commentBody = $(divcomment).find('#display-comment').text();
    $('#comment-body').val(commentBody);
    $('#edit-comment').modal();
  });

  $('#modal-save').click(function() {
    /*$.ajax({
        method: 'PUT',
        url: urlEdit,
        data: {
          comment: $('#comment').val(),
          commentId: commentId,
          _token: token
        }
      })
      .done(function(msg) {
        $(divcomment).text(msg['new_comment']);
        $('#edit-comment').modal('hide');
      });*/
    console.log("comment id: " + commentId + " comment: " + $('#comment-body').val());
  });

});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div class="modal fade" id="edit-comment" tabindex="-1" role="dialog">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
        <h4 class="modal-title" style="color:#000;">Editar Comentario</h4>
      </div>
      <div class="modal-body">
        <form>
          <div class="form-group">
            <label for="comment">Editar comentario</label>
            <textarea class="form-control" name="comment" id="comment"></textarea>
          </div>
        </form>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn-comment-dismiss btn-comment-modal" data-dismiss="modal"><span class="glyphicon glyphicon-remove"></span> Cerrar</button>
        <button type="button" class="btn-comment-edit btn-comment-modal" id="modal-save"><span class="glyphicon glyphicon-ok"></span> Editar</button>
      </div>
    </div>
  </div>
</div>
<article class="row">
  <div class="col-md-3 col-sm-3 hidden-xs">
    <figure class="thumbnail">
      <img class="img-responsive" src="http://placehold.it/200x200" />
      <figcaption class="text-center">User1</figcaption>
    </figure>
  </div>
  <div class="col-md-8 col-sm-8">
    <div class="panel panel-default arrow left">
      <div class="panel-body">
        <header class="text-left">
          <div class="comment-user"><i class="fa fa-user"></i>User1</div>
          <time class="comment-date" datetime="1 hour ago"><i class="fa fa-clock-o"></i>1 hour ago</time>
        </header>
        <div id="comment-post" data-commentid="1">
          <p id="display-comment">blah blah</p>
        </div>
      </div>

      <div class="panel-footer list-inline comment-footer">
        <a href="#" data-toggle="modal" data-target="edit-comment" class="edit-comment">Editar</a> <a href="#" data-toggle="modal" data-target="delete-comment" class="delete-comment">Eliminar</a>
      </div>
    </div>
  </div>
</article>

Now, aside from that, I am not entirely sure if browsers support the PUT method yet, thus, it may be necessary to add it as a property to your data array that you're sending in your ajax request, as well as change the ajax method to POST, like so:

$.ajax({
  method: 'POST',
  url: urlEdit,
  data: {
    comment: $('#comment').val(),
    commentId: commentId,
    _token: token,
    _method: 'PUT'
  }
})
.done(function(msg) {
  $(divcomment).text(msg['new_comment']);
  $('#edit-comment').modal('hide');
});

Finally, on the Laravel side of things, your code looks fine, though you may need a better method of comparing the authenticated user with the logged in user.

Of note; you are validating the existence of the comment request variable in your controller's update method. So if the variable is empty or an empty string, an error will be thrown by the validator. I'd have to check specifically how the validator works before I'd be able to provide any code in that regard.

Update: As it turns out, in your ajax you have the following:

comment: $('#comment-body').val(),

And that is not the id you gave for that textarea. The id you gave was comment, or in other words, your code should be this:

comment: $('#comment').val(),

I've thus updated the above examples to reflect this change.

Daedalus
  • 7,586
  • 5
  • 36
  • 61
  • hi, i made the changes and console gaves me the ID but, when i remove the console.log and complete the code "js" i get this error: {comment: ["Comment field is required."]} comment : ["Comment field is required."] – Juan Rincón Jun 04 '17 at 02:32
  • @JuanRincón And you are submitting the edit with content in the comment, right? – Daedalus Jun 04 '17 at 02:48
  • @JuanRincón The next step is to dump your $request variable to make sure the data is indeed there. – Daedalus Jun 04 '17 at 03:15
  • If i use method: 'POST' and _method: 'POST' and Route::POST i get this {comment: ["Comment field is required."]} comment : ["Comment field is required."], now if i use method: 'POST and _method: 'PUT' and Route::PUT i get this: POST http://devmedia.dev/comments/update 405 (Method Not Allowed). I can post a screenshot to show you the browser whole error – Juan Rincón Jun 04 '17 at 03:22
  • @JuanRincón Dump the `$request` variable like I suggested. – Daedalus Jun 04 '17 at 03:24
  • ehm how can i do that ? – Juan Rincón Jun 04 '17 at 03:27
  • @JuanRincón Depending on your laravel installation; `dd($request);` or `var_dump($request); die;`. – Daedalus Jun 04 '17 at 03:29
  • oh the die and dump. I can't get the dd results, the only thing i get is {comment: ["Comment field is required."]} comment : ["Comment field is required."] and i can't see the id: http://devmedia.dev/comments/update 422 (Unprocessable Entity) i think it should have the /comments/update/id – Juan Rincón Jun 04 '17 at 03:44
  • @JuanRincón Put the dump at the start of the update method, before any validation code occurs. So that it is the first thing in the function; to debug further we need to know if the request contains the variable or not. – Daedalus Jun 04 '17 at 03:47
  • Form Data: commentId: 2, _token: tI5KT0eMpm8fbb98bLQXByMLCiflb4ULlAkA2XCZ, _method: POST and Request URL:http://devmedia.dev/comments/update Request Method:POST Status Code:422 Unprocessable Entity Remote Address:127.0.0.1:80 Referrer Policy:no-referrer-when-downgrade but i think that isn't the dd result.. – Juan Rincón Jun 04 '17 at 03:59
  • @JuanRincón Looks like it is, and it looks like your js isn't sending the comment data. Checking the js. – Daedalus Jun 04 '17 at 04:13
  • Correct, now i'm getting the ID and the comment but a new error has appears: Status Code:500 Internal Server Error. And the error says: 1/3 SQLSTATE[23000]:Integrity constraint violation:1048 Column 'post_id' cannot be null. I will dd the request – Juan Rincón Jun 04 '17 at 04:44
  • @JuanRincón That's a separate question. So ask it as a new question, but essentially, you have a foreign key constraint somewhere, and your model updates your code is not respecting that constraint. – Daedalus Jun 04 '17 at 04:45
  • I am able to update the comment without the jquery and works, but as i said i'm really bad with js, probably the post_id left on my js code. i will make a new question – Juan Rincón Jun 04 '17 at 04:52
  • @JuanRincón In the mean time, please consider accepting this answer if it solved the problem presented in this question. Also I have a sneaking suspicion the problem is because the id is not cast to number, but is a string. I could be wrong though. – Daedalus Jun 04 '17 at 04:54
  • That's probably, i appreciate your time a lot. I posted the new question here: [link](https://stackoverflow.com/questions/44350927/error-500-internal-server-error-ajax-and-laravel) – Juan Rincón Jun 04 '17 at 05:07
  • @JuanRincón For more information, please see [this help page](https://stackoverflow.com/help/accepted-answer); accepting an answer grants reputation to the one who answered, as well as the asker. – Daedalus Jun 04 '17 at 05:45
  • @JuanRincón You'll have to be more specific. I would suggest another question, to explain why what I suggested isn't working for you. – Daedalus Jun 06 '17 at 22:27
  • Here it is [link](https://stackoverflow.com/questions/44400474/how-to-load-specific-div-or-id-ajax-and-laravel) – Juan Rincón Jun 06 '17 at 22:37
0

you are returning json response from your controller so add dataType:'json' in your ajax. Check the route in yours routes file. It must be a resource type or put type to accept the put request as

Route::resource($uri, $callback);

or

Route::put($uri, $callback);

Since HTML forms only support POST and GET, PUT and DELETE methods will be spoofed by automatically adding a _method hidden field to your form as

<input name="_method" type="hidden" value="PUT">
RAUSHAN KUMAR
  • 5,846
  • 4
  • 34
  • 70
0

This should fix it, I'm assuming you are using the latest version of laravel

public function update(Request $request)
{

    $this->validate($request, [
        'comment' => 'required'
    ]);

    if (! $comment = Comment::find($request->get('commentId'))) {
        // Comment not found.
        return redirect()->back();
    }

    if (Auth::user()->id != $comment->user->id) {
        return redirect()->back();
    }

    $comment = tap($comment)->update([
        'comment' => $request->get('comment'),
    ]);

    return response()->json(['new_comment' => $comment->comment], 200);

}

ps: all the response type should be the same.

Jorge Y. C. Rodriguez
  • 3,394
  • 5
  • 38
  • 61
  • I tried but now i'm getting this: `{comment: ["Comment field is required."]} comment : ["Comment field is required."]` – Juan Rincón Jun 03 '17 at 22:32
  • Do you send the comment in the request? Is because the comment is missing – Jorge Y. C. Rodriguez Jun 04 '17 at 05:12
  • @JuanRincón if you see https://stackoverflow.com/a/44349202/930306 he did a good solution for the front end – Jorge Y. C. Rodriguez Jun 04 '17 at 05:58
  • yes thanks to him it works but now i'm facing that problem with the post id – Juan Rincón Jun 04 '17 at 06:06
  • @JuanRincón is just because you are missing from sending that in the front end, if you go to the controller and `dd($request->get('commentId'))` it should display something, also I didn't see that error in your code before... see my updated answer – Jorge Y. C. Rodriguez Jun 04 '17 at 08:39
  • Now i'm getting the comment_id but, the problem now is with post_id, i need the post_id to reffer the comment to each post. I'm able to get the post_id when creating a new comment, even i'm able to edit a comment "but only php, no js", i'm trying to edit those comment with js, to not reload the page – Juan Rincón Jun 04 '17 at 08:48
  • I would probably use model binding to be able to inject comments in a post, and also create comments to given post, can you update the question and show how you relate models. Post-> comments and also how do you create the routes? do you use binding? – Jorge Y. C. Rodriguez Jun 04 '17 at 08:59