Uncaught (in promise) TypeError: Cannot read properties of null (reading 'name') in vue 3

Viewed 37

I'm completely new to vue and is following this simple example about real time socket message, but i got the error as the title mentioned, after i enter the name, when i type in the message and press send, it return error. it's in this 2 lines

          <div v-for="message in messages" :key="message">
            [{{ message.name }}]: {{ message.text }}

my full source of app.vue

<script setup>
  import { io } from 'socket.io-client'
  import { onBeforeMount, ref } from 'vue';

  const socket = io('http://localhost:3000');
  
  const messages = ref([]); 
  const messageText = ref('');
  const joined = ref(false);
  const name = ref('');
  const typingDisplay = ref('');

  onBeforeMount(() => {
    socket.emit('findAllMessages', {}, (response) => {
      messages.value = response;
    });
    
    socket.on('message', (message) => {
      messages.value.push(message);
    });

    socket.on('typing', ({name, isTyping}) => {
      if (isTyping) {
        typingDisplay.value = `${name} is typing...`;
      } else {
        typingDisplay.value = '';
      }
    });
  });
   
  const join = () => {
    socket.emit('join', {name: name.value}, () => {
      joined.value = true;
    });
  };

  const sendMessage = () => {
    socket.emit('createMessage', { text: messageText.value}, () => {
      messageText.value = '';
    });
  };
  
  let timeout;
  const emitTyping = () => {
    socket.emit('typing', {isTyping: true});
    timeout = setTimeout(() => {
      socket.emit('typing', {isTyping: false});
    }, 2000);
  };
  </script>
  
  <template>
    <div class="chat">
      <div v-if="!joined">
        <form @submit.prevent="join">
          <label>What's your name?</label>
          <input v-model="name" />
          <button type="submit">Send</button>
        </form>  
      </div>
      <div class="chat-container" v-else>
        <div class="messages-container">
          <div v-for="message in messages" :key="message">
            [{{ message.name }}]: {{ message.text }}
          </div>
        </div>

        <div v-if="typingDisplay">{{ typingDisplay}}</div>

        <hr/>

        <div class="message-input">
          <form @submit.prevent="sendMessage">
              <label>Message:</label>
              <input v-model="messageText" @input="emitTyping" />

              <button type="submit">Send</button>
          </form>
        </div>

      </div> 
    </div> 
  </template>
  
  <style >
  @import './assets/base.css';
  
  .chat{
    padding:20px;
    height: 100vh;
  }

  .chat-container{
    display: flex;
    flex-direction: column;
    height: 100%;
  }

  .message-container{
    flex: 1;
  }
  
  </style>
  
1 Answers

I can't see anything wrong with the code itself. Though the key of an element should generally not be assigned an object, but I doubt this would cause the issue you mention.

I assume either the code is not handling the message object correctly, because of which the 'name' property is not filled, or the object is being read in the HTML before it's actually filled. I would suggest further console logging in the process prior to the HTML render to see if the object is being filled with the appropriate data.

Related