Messages Component

Messages Vue component represents Messages component.

Messages Components

There are following components included:

  • f7-messages - main Messages container
  • f7-message - single message element
  • f7-messages-title - single messages title element

Messages Properties

Prop Type Default Description
<f7-messages> properties
init boolean true Initializes Messages component
new-messages-first boolean false Enable if you want to use new messages on top, instead of having them on bottom
scroll-messages boolean true Enable/disable messages autoscrolling when adding new message
scroll-messages-on-edge boolean true If enabled then messages autoscrolling will happen only when user is on top/bottom of the messages view
<f7-message> properties
type string sent Message type: sent (default) or received
text string Message text
avatar string Message user's avatar URL
name string Message user's name
image string Message image URL
header string Message header
footer string Message footer
text-header string Message text header
text-footer string Message text footer
first boolean false Defines that the message is first in the conversation
last boolean false Defines that the message is last in the conversation
tail boolean false Defines that the message has visual "tail". Usually last message in conversation
same-name boolean false Defines that this message sender name is the same as on previous message
same-header boolean false Defines that this message header text is the same as on previous message
same-footer boolean false Defines that this message footer text is the same as on previous message
same-avatar boolean false Defines that this message user's avatar URL is the same as on previous message

Messages Methods

<f7-messages> methods
.scroll(duration, position); Scroll messages to top/bottom depending on newMessagesFirst parameter
  • duration - number scroll duration in ms
  • position - number scroll position in px
.showTyping(message); Show typing message indicator
.hideTyping() Hide typing message indicator

Messages Events

Event Description
<f7-message> events
click Event will be triggered when user clicks on message bubble
click:name Event will be triggered when user clicks on message user's name
click:text Event will be triggered when user clicks on message text
click:avatar Event will be triggered when user clicks on message user's avatar
click:header Event will be triggered when user clicks on message header
click:footer Event will be triggered when user clicks on message footer
click:bubble Event will be triggered when user clicks on message bubble

Messages Slots

Single message Vue component (<f7-message>) has additional slots for custom elements:

  • default - element will be inserted as a child of <div class="message-bubble"> element in the end
  • start - element will be inserted in the beginning and direct child of main message element <div class="message">
  • end - element will be inserted in the end and direct child of main message element <div class="message">
  • content-start - element will be inserted in the beginning and direct child of the <div class="message-content"> element
  • content-end - element will be inserted in the end and direct child of the <div class="message-content"> element
  • bubble-start - element will be inserted in the beginning and direct child of the <div class="message-bubble"> element
  • bubble-end - element will be inserted in the end and direct child of the <div class="message-bubble"> element. Same as default slot

The following slots can be used inside of single message instead of same props if you need to pass there more complext layout:

  • header - element will be inserted in message header
  • footer - element will be inserted in message footer
  • text - element will be inserted in message text
  • name - element will be inserted in message name
  • image - element will be inserted in message image (supposed tp be an <img> element)
  • text-header - element will be inserted in message text header
  • text-footer - element will be inserted in message text footer
<f7-message
  type="sent"
  text="Hello World"
  name="John Doe"
  avatar="path/to/image.jpg"
>
  <div slot="start">Start</div>
  <div slot="end">End</div>
  <div slot="content-start">Content Start</div>
  <div slot="content-end">Content End</div>
  <div slot="bubble-start">Bubble Start</div>
  <div slot="bubble-end">Bubble End</div>
</f7-message>

<!-- Renders to: -->

<div class="message message-sent">
  <div>Start</div>
  <div class="message-avatar" style="background-image: url(path/to/image.jpg);"></div>
  <div class="message-content">
    <div>Content Start</div>
    <div class="message-name">John Doe</div>
    <div class="message-bubble">
      <div>Bubble Start</div>
      <div class="message-text">Hello World</div>
      <div>Bubble End</div>
    </div>
    <div>Content End</div>
  </div>
  <div>End</div>
</div>

Access To Messages Instance

If you use automatic initalization to init Messages (with init:true prop) and need to use Messages API you can access its initialized instance by accessing .f7Messages component's property.

Examples

<f7-messages>
  <f7-message name="John" text="Hello, Kate!" type="received"></f7-message>
  <f7-message name="Kate" text="Hi, John!" type="sent"></f7-message>
</f7-messages>

<!-- Renders to: -->

<div class="messages">
  <div class="message message-received">
    <div class="message-name">John</div>
    <div class="message-text">Hello, Kate!</div>
  </div>
  <div class="message message-sent">
    <div class="message-name">Kate</div>
    <div class="message-text">Hi, John!</div>
  </div>
</div>

Full Example

Here is how it can be used in Vue component along with Messagebar:

<template>
  <f7-page>
    <f7-navbar title="Messsages" back-link="Back"></f7-navbar>

    <!-- Messagebar -->
    <f7-messagebar
      placeholder="Send message"
      ref="messagebar"
    >
      <!-- Send message link -->
      <f7-link
        icon-if-ios="f7:arrow_up_fill"
        icon-if-md="material:send"
        slot="inner-end"
        @click="sendMessage"
      ></f7-link>
    </f7-messagebar>

    <!-- Messages -->
    <f7-messages ref="messages">
      <f7-messages-title><b>Sunday, Feb 9,</b> 12:58</f7-messages-title>
      <f7-message
        v-for="(message, index) in messagesData"
        :key="index"
        :type="message.type"
        :text="message.text"
        :image="message.image"
        :name="message.name"
        :avatar="message.avatar"
        :first="isFirstMessage(message, index)"
        :last="isLastMessage(message, index)"
        :tail="isTailMessage(message, index)"
      ></f7-message>
    </f7-messages>
  </f7-page>
</template>
<script>
  export default {
    data() {
      return {
        // Initial messages
        messagesData: [
          {
            type: 'sent',
            text: 'Hi, Kate',
          },
          {
            type: 'sent',
            text: 'How are you?',
          },
          {
            name: 'Kate',
            type: 'received',
            text: 'Hi, I am good!',
            avatar: 'http://lorempixel.com/100/100/people/9',
          },
          {
            name: 'Blue Ninja',
            type: 'received',
            text: 'Hi there, I am also fine, thanks! And how are you?',
            avatar: 'http://lorempixel.com/100/100/people/7',
          },
          {
            type: 'sent',
            text: 'Hey, Blue Ninja! Glad to see you ;)',
          },
          {
            type: 'sent',
            text: 'Hey, look, cutest kitten ever!',
          },
          {
            type: 'sent',
            image: 'http://lorempixel.com/200/260/cats/4/',

          },
          {
            name: 'Kate',
            type: 'received',
            text: 'Nice!',
            avatar: 'http://lorempixel.com/100/100/people/9',
          },
          {
            name: 'Kate',
            type: 'received',
            text: 'Like it very much!',
            avatar: 'http://lorempixel.com/100/100/people/9',
          },
          {
            name: 'Blue Ninja',
            type: 'received',
            text: 'Awesome!',
            avatar: 'http://lorempixel.com/100/100/people/7',
          },
        ],
        // Dummy data
        people: [
          {
            name: 'Kate Johnson',
            avatar: 'http://lorempixel.com/100/100/people/9',
          },
          {
            name: 'Blue Ninja',
            avatar: 'http://lorempixel.com/100/100/people/7',
          },
        ],
        answers: [
          'Yes!',
          'No',
          'Hm...',
          'I am not sure',
          'And what about you?',
          'May be ;)',
          'Lorem ipsum dolor sit amet, consectetur',
          'What?',
          'Are you sure?',
          'Of course',
          'Need to think about it',
          'Amazing!!!',
        ],
        // Response in progress flag
        responseInProgress: false,
      };
    },
    methods: {
      // Messages rules for correct styling
      isFirstMessage(message, index) {
        const self = this;
        const previousMessage = self.messagesData[index - 1];
        if (message.isTitle) return false;
        if (!previousMessage || previousMessage.type !== message.type || previousMessage.name !== message.name) return true;
        return false;
      },
      isLastMessage(message, index) {
        const self = this;
        const nextMessage = self.messagesData[index + 1];
        if (message.isTitle) return false;
        if (!nextMessage || nextMessage.type !== message.type || nextMessage.name !== message.name) return true;
        return false;
      },
      isTailMessage(message, index) {
        const self = this;
        const nextMessage = self.messagesData[index + 1];
        if (message.isTitle) return false;
        if (!nextMessage || nextMessage.type !== message.type || nextMessage.name !== message.name) return true;
        return false;
      },
      sendMessage() {
        const self = this;
        const text = self.messagebar.getValue().replace(/\n/g, '<br>').trim();

        if (text.length === 0) {
          // exit when empty messagebar text is empty
          return;
        }

        // Clear messagebar area
        self.messagebar.clear();

        // Focus area
        if (text.length) self.messagebar.focus();

        // Add sent message
        self.messagesData.push({
          text,
        });

        // Mock response
        if (self.responseInProgress) return;
        self.responseInProgress = true;
        setTimeout(() => {
          const answer = self.answers[Math.floor(Math.random() * self.answers.length)];
          const person = self.people[Math.floor(Math.random() * self.people.length)];
          self.messages.showTyping({
            header: `${person.name} is typing`,
            avatar: person.avatar,
          });
          setTimeout(() => {
            self.messagesData.push({
              text: answer,
              type: 'received',
              name: person.name,
              avatar: person.avatar,
            });
            self.messages.hideTyping();
            self.responseInProgress = false;
          }, 4000);
        }, 1000);
      },
      onF7Ready() {
        const self = this;
        // References to us APIs
        self.messagebar = self.$refs.messagebar.f7Messagebar;
        self.messages = self.$refs.messages.f7Messages;
      },
    },
  };
</script>