Fork me on GitHub

WhatsApp Clone with Meteor CLI and Ionic

Send image messages

Note: If you skipped ahead to this section, click here to download a zip of the tutorial at this point.

Our last step would be implementing image messages support. We will use the same package from the previous step to achieve that.

So we will use the same logic of taking the picture in the controller, and call the same newMessage() server method:

1
2
3
4
5
6
7
 
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
 
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import Ionic from 'ionic-scripts';
import { _ } from 'meteor/underscore';
import { Meteor } from 'meteor/meteor';
import { MeteorCameraUI } from 'meteor/okland:camera-ui';
import { Controller } from 'angular-ecmascript/module-helpers';
import { Chats, Messages } from '../../../lib/collections';
 
...some lines skipped...
    this.autoScroll();
  }
 
  sendPicture() {
    MeteorCameraUI.getPicture({}, (err, data) => {
      if (err) return this.handleError(err);
 
      this.callMethod('newMessage', {
        picture: data,
        type: 'picture',
        chatId: this.chatId
      });
    });
  }
 
  sendMessage() {
    if (_.isEmpty(this.message)) return;
 
...some lines skipped...
      this.$ionicScrollDelegate.$getByHandle('chatScroll').scrollBottom(animate);
    }, 300);
  }
 
  handleError(err) {
    if (err.error == 'cancel') return;
    this.$log.error('Profile save error ', err);
 
    this.$ionicPopup.alert({
      title: err.reason || 'Save failed',
      template: 'Please try again',
      okType: 'button-positive button-clear'
    });
  }
}
 
ChatCtrl.$name = 'ChatCtrl';
ChatCtrl.$inject = ['$stateParams', '$timeout', '$ionicScrollDelegate', '$ionicPopup', '$log'];

And now we need to register an ng-click event to the image button on the view:

8.2 Invoke send picture logic on click client/templates/chat.html
28
29
30
31
32
33
34
      <button ng-click="chat.sendMessage()" class="button button-clear button-positive">Send</button>
    </span>
    <span ng-if="!chat.message || chat.message.length === 0">
      <button ng-click="chat.sendPicture()" class="button button-clear button-icon button-positive icon ion-ios-camera-outline"></button>
      <i class="buttons-seperator icon ion-android-more-vertical"></i>
      <button class="button button-clear button-icon button-positive icon ion-ios-mic-outline"></button>
    </span>

In the server, we need to add a validation scheme for image messages in the newMessage() method:

8.3 Add picture message validation lib/methods.js
1
2
3
4
5
 
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import { Chats, Messages } from '../lib/collections';
 
Meteor.methods({
...some lines skipped...
        'Must be logged in to send message.');
    }
 
    check(message, Match.OneOf(
      {
        text: String,
        type: String,
        chatId: String
      },
      {
        picture: String,
        type: String,
        chatId: String
      }
    ));
 
    message.timestamp = new Date();
    message.userId = this.userId;

Our next step would be updating the chat view to support image messages:

8.4 Add picture message type to chat view client/templates/chat.html
6
7
8
9
10
11
12
13
14
15
16
17
    <div class="message-list">
      <div ng-repeat="message in chat.messages" class="message-wrapper">
        <div class="message" ng-class="message.userId === $root.currentUser._id ? 'message-mine' : 'message-other'">
          <ng-switch on="message.type">
            <div ng-switch-when="text" class="text">{{ message.text }}</div>
            <div ng-switch-when="picture" class="picture">
              <img ng-src="{{ message.picture }}">
            </div>
          </ng-switch>
          <span class="message-timestamp">{{ message.timestamp | amDateFormat: 'HH:mm' }}</span>
        </div>
      </div>

Let's add some css to prevent images from looking silly:

8.5 Add picture style to chat stylesheet client/styles/chat.scss
66
67
68
69
70
71
72
 
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
    background-image: url(/message-mine.png)
  }
 
  .text {
    padding: 5px 7px;
    word-wrap: break-word;
 
...some lines skipped...
    }
  }
 
  .picture {
    padding: 4px 4px 0;
 
    img {
      width: 220px;
      height: 130px;
      border-radius: 6px;
    }
  }
 
  .message-timestamp {
    position: absolute;
    bottom: 2px;

We also want to add image icon on the chats list in case when the last message is an image message, so let's add it:

8.6 Add picture message indication in chats view client/templates/chats.html
11
12
13
14
15
16
17
18
19
20
                href="#/tab/chats/{{ chat._id }}">
        <img ng-src="{{ chat | chatPicture }}">
        <h2>{{ chat | chatName }}</h2>
        <ng-switch on="chat.lastMessage.type">
          <p ng-switch-when="text">{{ chat.lastMessage.text }}</p>
          <p ng-switch-when="picture">image</p>
        </ng-switch>
        <span class="last-message-timestamp">{{ chat.lastMessage.timestamp | calendar }}</span>
        <i class="icon ion-chevron-right icon-accessory"></i>
        <ion-option-button class="button-assertive" ng-click="chats.remove(chat)">