Search code examples
laravellaravel-livewire

Livewire: Unable to update child components after adding new record


I have an issue I can't get my head around. I have set up a structure of components as:

Post -> Comment -> CommentReply

CommentReply emits an event captured by Post. Post updates the comments collection.

The Comment (Model) has self relation as responses.

Now if the comment is top level the view is updated. But if the responses relation is updated the view don't show the update. If I emit a refresh event that is mapped to $refresh in Comment (component) the component throws error:

Uncaught (in promise) TypeError: Cannot read property 'fingerprint' of null

UPDATE

CommentReply.php

public function post_reply () {
     ...
    $new_comment = $this->comment->response()->create($c);
    $this->is_replying = false;
    $this->emit('content:comments:replied', $new_comment);
}

Comment.php (component)

    public $listeners = [
        'content:comments:replied' => 'replied'
    ];

   public function replied($comment) {
        /*
           received as array because type hinting
           created error of array to string conversion
       */
        $c = new CommentModel($comment); 
        $this->comment->responses->prepend($c);
    }

comment.blade.php

<div>
@foreach($comment->responses as $response)
<div>
     <div>
         {{ $response->comment }}
     </div>

     <livewire:comment-reply :comment="$comment" :key="'comment-' . $response->id" />
</div>
@endforeach
</div>

comment-reply.blade.php

<div x-data="{ replying: @entangle('is_replying') }">
    <button @click="replying = true;" x-show="!replying">Reply</button>
   <div x-show="replying">
       <textarea wire:model.defer="c.comment"></textarea>
       <button wire:click="post_reply">Post</button>
    </div>
</div>

Solution

  • So here is how I went by this...

    1. Created a component CommentView and moved the comment display logic to this component comment-view.blade.php
    <div>
         <div>
             {{ $comment->comment }}
         </div>
    
         <livewire:comment-reply :comment="$comment" />
    </div>
    
    1. Comment component has two variables now, the $comment and $responses, every time the CommentReply emits the content:comments:replied the $responses variable is refreshed.

    Comment.php

        public $listeners = [
            'content:comments:replied' => 'replied'
        ];
    
       public function replied() {
            $this->responses = $this->comment->responses()->orderBy('created_at', 'desc')->get();
        }
    
    

    comment.blade.php

    <div>
        <livewire:comment-view :comment="$comment" />
        @foreach($responses as $r_comment) 
              <livewire:comment-view :comment="$r_comment" :key="'response-' . $r_comment->id" />
         @endforeach
    </div>