laravelvue.jspusher-js

Error accessing property in Vue 3 with Axios and Laravel Echo: Cannot read properties of undefined (reading 'discussion_id')


`Problem Description:

I'm working on a chat application using Vue 3, Axios, and Laravel Echo (with Pusher) for real-time updates. I'm encountering an issue where I receive the following error:

``ChatArtisanClient.vue:68 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'discussion_id')
    at ChatArtisanClient.vue:68:52
    at renderList (chunk-U6BEPC57.js?v=670d87f9:4352:16)
    at ChatArtisanClient.vue:1:1

In my onMounted lifecycle hook, I fetch initial messages and set up a listener for real-time updates as follows:`

`class MessageNotification implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $message;
    public $user;
    public $taskId;
    public $userId;

    public function __construct($message, $user, $taskId, $userId)
    {
        $this->message = $message;
        $this->user = $user;
        $this->taskId = $taskId;
        $this->userId = $userId;
    }

    public function broadcastOn()
    {
        return new PrivateChannel('task.' . $this->taskId . 'user.' . $this->userId);
    }
}`

`Broadcast::channel('App.Models.User.{id}', function ($user, $id) {
    return (int) $user->id === (int) $id;
});

use Illuminate\Support\Facades\Log;

Broadcast::channel('task.{taskId}.user.{userId}', function ($user, $taskId, $userId) {
    Log::info('Tentative de connexion au canal privé', ['user_id' => $user->id, 'task_id' => $taskId, 'userId' => $userId]);

    $discussion = Discussion::where('task_id', $taskId)
                            ->where('artisan_user_id', $user->id)
                            ->first();

    if (!$discussion) {
        Log::warning('Aucune discussion trouvée', ['user_id' => $user->id, 'task_id' => $taskId]);
        return false;
    }

    Log::info('Discussion trouvée', ['discussion_id' => $discussion->id, 'task_id' => $taskId, 'artisan_user_id' => $discussion->artisan_user_id, 'client_user_id' => $discussion->user_id]);

    $isParticipant = $discussion->user_id === $userId || $discussion->artisan_user_id === $user->id;
    Log::info('Vérification des participants', ['is_participant' => $isParticipant]);

    return $isParticipant;
});
`


`use App\Events\MessageNotification;
use App\Notifications\NewMessageNotification;

class ChatsController extends Controller
{

    public function index()
    {
        $messages = Message::with('user')->get();
        return Inertia::render('Chat', compact('messages'));
    }

    public function fetchMessages()
    {
        return Message::with('user')->get();
    }


    public function store(Request $request)
    {
        // Récupérer l'utilisateur authentifié (ici l'artisan)
        $artisan = Auth::user();
        $taskId = $request->taskId;

        // Récupérer l'utilisateur (le client) associé à la tâche
        $task = Task::find($taskId);

        $userId = $task->user_id; // Identifiant du client

        // Vérifier si une discussion existe déjà entre l'artisan et le client pour la tâche
        $discussion = Discussion::where('task_id', $taskId)
                                ->where('artisan_user_id', $artisan->id)
                                ->first();

        // Si aucune discussion n'existe, en créer une nouvelle
        if (!$discussion) {
            $discussion = Discussion::create([
                'task_id' => $taskId,
                'user_id' => $userId, // Identifiant du client
                'artisan_user_id' => $artisan->id // Identifiant de l'artisan
            ]);
        }

        // Créer un nouveau message dans la discussion
        $message = $discussion->messages()->create([
            'user_id' => $artisan->id, // Identifiant de l'utilisateur envoyant le message (l'artisan ici)
            'message' => $request->message,
        ]);

         // Diffuser l'événement sur le canal privé basé sur les IDs des utilisateurs
    broadcast(new MessageNotification($message, Auth::user(), $taskId, $artisan->id))->toOthers();

        return ['status' => 'Message envoyé'];
    }
}`
`const props = defineProps({
    taskId: Number,
    userId: Number
});

const msg = ref([]);
const form = useForm({
    message: "",
    taskId: props.taskId,
});

 onMounted(async () => {
      try {
        const response = await axios.get('/messages');
        msg.value = response.data;
        console.log("MessageNotification");

        // Placez ici le reste du code qui dépend de msg.value
        console.log(msg.value);
      } catch (error) {
        console.error('Erreur lors de la récupération des messages:', error);
      }
    });


    window.Echo.private(`task.${props.taskId}.user.${props.userId}`).listen('MessageNotification', (response) => {
        console.log("MessageNotification");
        console.log(response);
        msg.value.push({
            message: response.message.message,
            user: response.user
        });
        //alert('Show without refresh!');
    });

const submit = () => {
    axios.post("/chat", form).then((response) => {
        msg.value.push(response.data.message);
        form.message = null;
    });
};
</script>

<template>
<AppLayout title="Tâche">
    <Head title="Chat" />
    <template>
        <h2 class="font-semibold text-xl text-gray-800 leading-tight">Chat</h2>
    </template>
    <div class="py-12">`your text`
        <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
            <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
                <div class="font-bold text-xl mb-4 p-3">Messages</div>
                <hr/>
                <div class="overflow-y-auto max-h">
                    <ul class="chat list-none p-6">
                        <li v-for="(message, i) in msg" :key="i" class="left clearfix">
                            <div class="clearfix">
                                <div class="header">
                                    <strong class="text-blue-500">
                                        {{ message.discussion_id }} :
                                    </strong>
                                    {{ message.message }}
                                </div>
                            </div>
                        </li>
                    </ul>
                </div>
                <hr>
                <div class="mt-4 p-4">
                    <div class="flex items-center">
                        <input
                            id="btn-input"
                            type="text"
                            name="message"
                            class="border border-gray-200 rounded w-full"
                            v-model="form.message"
                            @keyup.enter="submit"
                            placeholder="Type your message here..."
                        />
                        <span class="ml-2">
                            <button class="bg-blue-500 text-white px-4 py-2 rounded" id="btn-chat" @click="submit">
                                Send
                            </button>
                        </span>
                    </div>
                </div>
            </div>
        </div>
    </div>
</AppLayout>
</template>`

The message already in the database are displays without any errors.

I tried to change the information retrieved and also checked the models; I expect everything is okay. I tried to display log messages, but the window.Echo part doesn't show anything.`


Solution

  • After doing some research, I figured out that my route wasn't displaying the error message correctly, so I added a try-catch block. I found out that my controller was showing some errors related to the fact that the parameters of the route were not being sent correctly, so I used the append method instead of sending the form, and it worked.

    const submit = async (e) => {
        e.preventDefault();
    
        var formData = new FormData();
    formData.append("message", form.message);
    formData.append("taskId", props.taskId);
    
        try {
            axios.post("/chat", formData).then((response) => {
            msg.value = response.data;
            form.message = null
            });
        } catch (error) {
            console.error('Erreur lors de l\'envoi du message:', error);
        }
    };