Skip to content

Vanilla JavaScript messenger or how to add private messages to your app

Mev-Rael edited this page Sep 8, 2016 · 1 revision

Today almost every app requires private message system and it takes weeks to make it.

Bunny Messenger is a vanilla JavaScript (ES6) private messanger framework for browser. It allows to easily build custom messengers and style them in any way.

All what you need is a back-end app or script with JSON API to get latest messages and create new ones. Probably you already have one or using any package. With Bunny Messenger focus only on your busines and app.

1. Server requirements

There should be a way to get user authentication state from Server on client-side. For example, server can just render in response a JS variable or may be you have some component, AJAX calls for that.

Server should have 3 API methods:

  1. To load latest N (per page) messages between currently authenticated user and user X, for example GET /api/messenger/read/{senderId}/{page=1}
  2. To check and load new messages since last message, for example GET /api/messenger/check/{senderId}/{lastMessageId}
  3. To create new messages, for example POST /api/messenger/create/{receiverId}/ and text as input param

Server should check for authentication itself.

1.1. read(senderId, page = 1) method JSON response:

First method should return data about the user (senderId) in user key and array of messages in messages key ordered by date created DESC and limited to any number per page you want, 20, for example.

{
  user: {
    id: 1,
    name: 'Bob',
    profileUrl: 'https://app.com/users/1',
    photoUrl: 'https://app.com/img/users/1.jpg'
  },
  messages: [
    {
      id: 20,
      message: 'Hello, world!',
      dateCreated: '2016-09-02T14:21:48+00:00', // (valid W3C/ISO string which can be passed to JS new Date('date string')
      senderId: 1,
      receiverId: 4
    },
    // rest message object...
  ]
}

1.2. check(senderId, lastMessageId) JSON response:

Second method should return only array of messages in same format as in previous read() method but ordered by date created ASC this time!

1.3. create(receiverId, text) JSON response:

Last POST method should return single message object and not an array:

2. JavaScript requirements

Now any model or state with AJAX calls required on client-side.

Each model method should return a Promise.

Create any JS object with next interface:

  • read(userId, page = 1)
    • should return data with at least 2 keys: user and messages in same format as described in Section 1.1
    • MessengerConfig.messagesPerPage should be same as server-side per page limit, defaults to 20.
    • should be ordered by date created DESC
  • create(userId, text)
    • creates new message to userId with message = text and receives a single message object
  • check(userId)
    • checks for new messages since last message each MessengerConfig.checkForNewMessagesInterval seconds (defaults to 30)
    • should return data same as read() but ordered by date created ASC not DESC

3. Markup (HTML, CSS) requirements

3.1. Add init attribute to all toggle buttons

Add attribute data-messenger="{userId} to all elements which should trigger messenger on click.

Usually they are "Send PM" buttons, profile pictures, etc.

Attribute value should be a non-empty and contain an ID for second user. If auth user and second user are the same, then attribute should not be added.

If there is DOM content loaded later and it is required to attach new events on new containers then Messenger.initToggles(container) can be used.

3.2. Create container for Messenger window itself

Create a single container for private messages with hidden attribute and ID = MessengerConfig.id ("pm" by default),

Container should have child elements:

  • header with
    • any element which will contain the name of the 2nd user (receiver) with ID = MessengerConfig.idName ("pm_name")
    • close button with ID = MessengerConfig.idClose
  • element with overflow Y only for messenger body (container for messages itself) with ID = MessengerConfig.idBody
  • footer with form containing one textarea with ID = MessengerConfig.idInput

Example:

<div id="pm" class="app-pm" hidden>

    <header class="app-pm-header">
        <span id="pm_name"></span>

        <button id="pm_close" class="pull-right app-btn-reset app-s-close-bold"></button>
    </header>

    <div id="pm_body" class="app-pm-body">

    </div>

    <footer class="app-pm-footer">
        <form>
            <textarea id="pm_input" placeholder="Type a message..." class="app-pm-input" type="text" name="pm"></textarea>
        </form>
    </footer>

</div>

3.3. Style container and each <message> as you want

Each message will have next markup:

<message data-id="{message.id}">
    <div>
       <a href="{user.profileUrl}">
          <img src="{user.photoUrl}">
       </a>
    </div>
    <p>{message.message}</p>
</message>

Answers (messages sent by auth user):

  • will have <message type="answer"> attribute
  • and will not have first child <div>, but only <p>

Time will be added between messages within <time></time>

4. Initializing Messenger

Finally on DOM ready initialize a Messenger with Messenger.init(Model, authCheck)

authCheck:

  • represents a current auth user state,
  • it should be a boolean or a result from any function or AJAX call,
  • it should be TRUE if user is authenticated and only then messenger will be initialized
import { Messenger } from 'bunnyjs/src/Messenger';
import { PrivateMessage } from '../Models/PrivateMessage';

document.addEventListener('DOMContentLoaded', () => {
    Messenger.init(PrivateMessage, Server.auth.check);
});