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

Time:09-16

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 >
      <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  v-else>
        <div >
          <div v-for="message in messages" :key="message">
            [{{ message.name }}]: {{ message.text }}
          </div>
        </div>

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

        <hr/>

        <div >
          <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>
  

CodePudding user response:

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