title: Javascript & Django Channels: Chat app sign off notification on window close
body: <p>I am writing a chat app with Javascript and Django Channels.  I am trying get a "User has left chat." message to send when the window is closed, maybe also when the websocket is closed.  I'm not sure if the websocket is closing too quickly, but the code as I have it currently is not working.  It's possible I should be defining within the disconnect function in the chat consumer. I'm not sure of the order some of this stuff is handled in.</p>
  
  <p>Javascript</p>
  
  <pre><code>// Declare variables
      var userName;
      var currentZone = new Date().toTimeString().slice(17);
      // var roomName = {{ room_name_json }};
      document.getElementById("chatname").innerHTML = roomName;
  
  // Create Websocket
      var chatSocket = new ReconnectingWebSocket(
          'ws://' + window.location.host +
          '/ws/chat/' + roomName + '/');
  
  // Send message
      chatSocket.onmessage = function(e) {
          var data = JSON.parse(e.data);
          var message = data['message'];
          document.querySelector('#chat-log').value += (message + '\n');
          document.getElementById("chat-log").scrollTop = document.getElementById("chat-log").scrollHeight;
      };
  
  // Set User
      window.onload = function(){
          userName = sessionStorage.getItem("user");
          if (userName==null || userName===false) {
              userName = prompt("Please enter a username:");
          };
          return userName;
      }
  
  //Join message
      function chatJoin() {
          if(chatSocket.readyState == false) {
             window.setTimeout(chatJoin, 500); /* Wait 500 milliseconds*/
          } else {
              var message = userName + " has joined the chat."
              chatSocket.send(JSON.stringify({
                  'message': message
              }));
          }
      }
      chatJoin();
  
      // chatSocket.onclose = function(e) {
      //     console.error('Chat socket closed unexpectedly');
      // };
  
  // Sign off message
      window.unload = function(e) {
          var message = userName +"has left the chat."
          chatSocket.send(JSON.stringify({
              'message': message
          }));
      };
  
      document.querySelector('#chat-message-input').focus();
      document.querySelector('#chat-message-input').onkeyup = function(e) {
          if (e.keyCode === 13) {  // enter, return
              document.querySelector('#chat-message-submit').click();
          }
      };
  
      document.querySelector('#chat-message-submit').onclick = function(e) {
          var currentDate = new Date();
          var currentTime = currentDate.toLocaleTimeString();
          var messageInputDom = document.querySelector('#chat-message-input');
          var message = userName + " " + currentTime + currentZone + ': ' + messageInputDom.value;
          chatSocket.send(JSON.stringify({
              'message': message
          }));
  
          messageInputDom.value = '';
      };
  </code></pre>
  
  <p>Consumer</p>
  
  <pre><code>from channels.generic.websocket import AsyncWebsocketConsumer
  from channels.generic.websocket import WebsocketConsumer
  
  import json
  
  class ChatConsumer(AsyncWebsocketConsumer):
      async def connect(self):
          self.room_name = self.scope['url_route']['kwargs']['room_name']
          self.room_group_name = 'chat_%s' % self.room_name
  
          # Join room group
          await self.channel_layer.group_add(
              self.room_group_name,
              self.channel_name
          )
  
          await self.accept()
  
      async def disconnect(self, close_code):
          # Leave room group
          await self.channel_layer.group_discard(
              self.room_group_name,
              self.channel_name
          )
  
      # Receive message from WebSocket
      async def receive(self, text_data):
          text_data_json = json.loads(text_data)
          message = text_data_json['message']
  
          # Send message to room group
          await self.channel_layer.group_send(
              self.room_group_name,
              {
                  'type': 'chat_message',
                  'message': message
              }
          )
  
      # Receive message from room group
      async def chat_message(self, event):
          message = event['message']
  
          # Send message to WebSocket
          await self.send(text_data=json.dumps({
              'message': message
          }))
  </code></pre>
  
  <p>I have also tried the disconnect function like this, I'd like to include the username in the message so it would need to receive some data:</p>
  
  <pre><code>    async def disconnect(self, text_data, close_code):
          text_data_json = json.loads(text_data)
          message = text_data_json['message']
  
          # Send message to room group
          await self.channel_layer.group_send(
              self.room_group_name,
              {
                  'type': 'chat_message',
                  'message': message
              }
          )
  
          # Leave room group
          await self.channel_layer.group_discard(
              self.room_group_name,
              self.channel_name
          )
  </code></pre>