Xây dựng ứng dụng chat đơn giản bằng Angularjs và PubNub

Giới thiệu

Dưới đây là một ứng dụng đơn giản giúp người dùng có thể chat trực tiếp với nhau, sử dụng AngularJs và PubNub. Bài viết mang tính chất giúp người đọc hiểu được khái quát về PubNub và sử dụng PubNub Angularjs SDK

Cài đặt PubNub Angularjs SDK

  1. Đăng ký tài khoản PubNub

    Đầu tiên, bận cần đăng ký một tài khoản tại https://admin.pubnub.com/#/login. Sau khi tạo tài khoản thành công bạn có thể dễ dàng tạo một project mới và lấy được publish key và subscribe key

  2. Sử dụng PubNub trong project

    Có 3 cách để sử dụng pubnub trong project

    • CDN:

<script src="https://cdn.pubnub.com/pubnub-3.7.21.js"></script> - NPM: npm install --save pubnub pubnub-angular

 -  Bower:

bower install --save pubnub pubnub-angular

Để sử dụng PubNub, ta cần khai báo trong file app.js như sau, với publish_key và subscribe_key là 2 key mà bạn đã lấy được sau khi tạo project trên trang PubNub ở trên

    angular.module("app",['ngCookies', 'ngSanitize','ui.router', 'pubnub.angular.service'])
      .config(config)
      .run(run);

      run.$inject = ['$rootScope', '$location', '$cookieStore', '$http','$route', "Pubnub"];
      function run($rootScope, $location, $cookieStore, $http, $route, Pubnub) {
        $rootScope.globals = $cookieStore.get('yang') || {};
        if ($rootScope.globals.currentUser) {
          $http.defaults.headers.common['Authorization'] = $rootScope.globals.currentUser.auth_token;
        }
        Pubnub.init({
            publish_key: 'publish_key',
            subscribe_key: 'subscribe_key',
            uuid: $rootScope.globals.currentUser.id
        });
       }

Giao diện và controller

  • Trước tiên ta cần tạo một state chat

        $stateProvider
            .state('chat',{
             url: '/chats/chat',
            templateUrl: "<%= asset_path('chats/chat.html') %>",
            controller: 'ChatCtrl',
            controllerAs: 'vm'
          });

  • Tạo MessageService

    MessageService bao gôm các function để subcribe một kênh, gửi message và nhận message từ kênh đó. Để các user có thể chat trực tiếp với nhau các user này phải gửi và nhận message từ cùng một kênh


      angular
        .module("app")
         .factory('MessageService', MessageServiceFactory)
      MessageService.$inject = ['$rootScope', '$pubnubChannel', '$rootScope'];
      function MessageServiceFactory($rootScope, $pubnubChannel, $rootScope) {
        var service = {};
        service.SendMessage = SendMessage;
        service.Subscribe = Subscribe;
        service.SubcribeNewMessage = SubcribeNewMessage;
        return service;
        function SendMessage(channel, messageContent) {
          if (messageContent == "")
            return;
          Pubnub.publish({
            channel: channel,
            message: {
              uuid: $rootScope.globals.currentUser.id,
              content: messageContent,
              sender_uuid: currentUser,
              date: Date.now()
            },
          });
        };

        function Subscribe(channel) {
          Pubnub.subscribe({
            channel: channel,
            triggerEvents: ['callback']
          });
        };

        function SubcribeNewMessage(channel) {
          $scope.$on(Pubnub.getMessageEventNameFor(vm.channel), function(ngEvent, m) {
            return m;
          });
        };
      };

  • Tạo controller ChatCtrl

      angular
        .module('app')
        .controller(ChatCtrl)
      ChatCtrl.$inject = ["$scope", "$rootScope", "MessageService", "UserService"];
      function ChatCtrl($scope, $rootScope, MessageService, UserService) {
        vm =this;
        vm.current_user = $rootScope.globals.currentUser;
        vm.channel = "messages-chanel";
        vm.messages = []
        vm.messageContent = '';
        vm.uuid = vm.current_user.id.toString();
        vm.sendMessage = function() {
           MessageService.sendMessage(vm.messageContent);
            vm.messageContent = '';
        }
        // Subscribe kênh message-chanel
        MessageService.subscribe(vm.channel);
        vm.scrollDown = function(time) {
            var $elem = $('.collection');
            $('body').animate({
                scrollTop: $elem.height()
            }, time);
        };
        vm.scrollDown(400);
        // Lấy các message về
        MessageService.SubcribeNewMessage(vm.channel).then(function(data) {
          if(data)
            vm.messages.push(data);
        });
    };

  • Tạo file html chats/chat.html

    <ul>
     <li ng-repeat="message in vm.messages">
       <img src="{{avatarUrl(vn.message.sender_uuid)}}" alt="{{vm.message.sender_uuid}}">
       <span>User #{{ message.sender_uuid }}</span>
       <p><span>{{ message.date | date:"MM/dd/yyyy 'at' h:mma"}}</span></br> {{ message.content }}</p>
     </li>
    </ul>
    <footer>
     <form ng-submit="vm.sendMessage()">
       <div class="row">
         <div>
           <input ng-model="vm.messageContent" type="text" placeholder="Type your message" >
           <span>
             <img src="{{vm.current_user.avatar}}">
            {{vm.current_user.name}} #{{uuid}}
           </span>
         </div>
         <div>
           <button type="submit">Submit</button>
         </div>
       </div>
      </form>
    </footer>

Trong bài viết này mình chỉ đề cập đến việc chat chung một kênh message-chanel. Tuy nhiên, để có thể tạo nhiều kênh chat giữa hai người dùng cũng rất đơn giản, bạn chỉ cần thêm một state /chats/:Id/chat và trong controller set vm.chanel bằng một giá trị tạo bởi 2 user đó, ví dụ như tạo bằng 2 id, tuy nhiên bạn phải chắc chắn rằng 2 user đang chat chung một kênh