我无法在Meteor应用程序中使用聊天功能

I am unable to get the chat functionality to work in my Meteor app

本文关键字:聊天 功能 应用程序 Meteor      更新时间:2023-09-26

你好,我是Meteor的新手,正在努力学习和熟悉Meteor平台。

所以我正在构建Meteor应用程序{https://github.com/ahadsheriff/SheriffMessenger}这是基于我看到的另一个例子{http://chatt.meteor.com/(注意:最初的应用程序是使用旧版本的流星构建的,其中一些包在当前版本中是不必要的(我的))我克隆示例应用程序的目的是用流星和应用程序本身进行实验,想法是(一旦我让它工作起来)分解代码,研究每个单独的元素,以了解流星是如何工作的。

在我的克隆中,除了两个主要功能在我的版本中不起作用外,一切看起来都很好:聊天/消息功能以及查看与哪个用户通信以及查看他们是否在线的功能。

我已经安装了我可能安装的所有软件包(Meteor最新版本中支持的软件包),我认为我的问题可能是缺少一些基本的软件包。

无论如何,我想知道是否有人能帮我筛选代码,看看我的问题在哪里,这样我就可以让应用程序正常工作,并重新分解这些代码!

感谢您的帮助!

我已经在上面发布了github链接,为了方便您,我将在下面发布HTML和Javascript代码。

谢谢你,我们将非常感谢你的帮助!!!

HTML:

<template name="layout">
  <head>
    <title>Simple chat</title>
    <link href='http://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>
  </head>
    <!-- Wrap all page content here -->
    {{> yield}}
</template>
<template name="channel">
    <div class="container">
      <div class="row">
        <div class="col-md-3">
          {{> presentation}}
        </div>
        <div class="col-md-6">
          {{> chat}}        
        </div>
        <div class="col-md-3">
          {{> participants}}
        </div>
      </div>
    </div>
</template>
<template name="homepage">
  <div class="container">
    <div class="row">
      <div class="col-md-6 col-md-offset-3">
        <div class="header">
          <a href="/"><h1>Sheriff Messenger</h1></a>
          <h2>Chat. Like a Sheriff.</h2>
        </div>
        <div class="landing">
          <form class="form-inline" role="form">
          <div class="form-group">
            <input type="text" class="form-control" id="channelInput" placeholder="username" maxlength="20" />
            <button type="button" id="channelButton" class="btn btn-default">enter</button>
          </div>
        </form>
        <div class="channels">
          <ul class="pager">
            {{#each channels}}
              <li><a href="/c/{{ name }}">{{ name }} - {{ participants.length }} <span class="glyphicon glyphicon-user"></span></a></li>
            {{/each}}
          </ul>
        </div>
        </div>
      </div>
    </div>
  </div>
</template>

<template name="presentation">
  <a href="/"><h1>Sheriff Messenger</h1></a>
</template>
<template name="participants">
  <h3>Participants</h3>
  <ul>
    {{#each participants}}
      <li style="list-style-type: none;"><div class="color-swatch" style="background-color:{{labelClass}};"></div> {{ profile.name }}</li>
    {{/each}}
  </ul>
  <p>Edit your name : </p>
  <input type="text" class="form-control" id="nameInput" placeholder="{{name}}" maxlength="40" />
</template>
<template name="chat">
  <div class="chat">
    <div class="conversation commentArea" id="scroll">
      {{#each messages }}
        {{#if message}}
          <div class="{{authorCss author}}">
            {{breaklines message }}<br/>
            <i class="author">{{ name }}</i>
          </div>
        {{else}}
          <div class="bubbledLeft">
            <i class="author">Sheriff Messenger</i>
          </div>
        {{/if}}
        <script> if (typeof(scrolldown) == "function") { scrolldown(); }</script>
      {{/each}}
    </div>
    <div class="conversationInput"> 
      <input type="text" id="messageInput" class="form-control text" placeholder="Message..." maxlength="300">
    </div>
  </div>

  <script type="text/javascript">
    /* Call it everytime ? ....
    around 10 times at the first call...
     */
    var scrolldown = function() {
      console.log("one scrolldown call..."); // reminder to debug...
      var elem = document.getElementById('scroll');
      elem.scrollTop = elem.scrollHeight;
    }
  </script>
</template>

Javascript:

var MeteorUser = function () {
  var userId = Meteor.userId();
  if (!userId) {
    return null;
  }
  var user = Meteor.users.findOne(userId);
  /* if (user !== undefined &&
      user.profile !== undefined &&
      user.profile.guest) {
    return null;
  } */
  return user;  
};

////////// Helpers for in-place editing //////////
// Returns an event map that handles the "escape" and "return" keys and
// "blur" events on a text input (given by selector) and interprets them
// as "ok" or "cancel".
var okCancelEvents = function (selector, callbacks) {
  var ok = callbacks.ok || function () {};
  var cancel = callbacks.cancel || function () {};
  var events = {};
  events['keyup '+selector+', keydown '+selector+', focusout '+selector] =
    function (evt) {
      if (evt.type === "keydown" && evt.which === 27) {
        // escape = cancel
        cancel.call(this, evt);
      } else if (evt.type === "keyup" && evt.which === 13 ||
                 evt.type === "focusout") {
        // blur/return/enter = ok/submit if non-empty
        var value = String(evt.target.value || "");
        if (value)
          ok.call(this, value, evt);
        else
          cancel.call(this, evt);
      }
    };
  return events;
};
var activateInput = function (input) {
  input.focus();
  input.select();
};
UI.registerHelper('breaklines', function(text){ // Should call a fonction to sanitaze the html...
  var html = "";
  if(text) { 
    html = text.replace(/('r'n|'n|'r)/gm, '<br>');
  }
  return Spacebars.SafeString(html);
});

// Not the right way to do it ?!!!
UI.registerHelper('authorCss', function(author){
  var cssClass = "bubbledLeft";
  if(author === Meteor.userId()) { 
    cssClass = "bubbledRight";
  }
  return cssClass;
});
/////////// End Helper ///////
if (Meteor.isClient) {
  // Create collection on client
  Messages = new Meteor.Collection('messages');
  Channels = new Meteor.Collection('channels');
  Meteor.startup(function() {
      Meteor.loginVisitor(); // Guest Account
      //Meteor.insecureUserLogin('Anonymous'); // Test Account
      // We take car of the name
      Session.setDefault('name', 'Guest');
      Session.setDefault('channel', 'yo');
  });

  //////////// Chat ///////////////
  Template.chat.messages = function () {
    var messagesCursor = Messages.find({}, {sort:{timestamp:-1}, limit:42});
    var messages = messagesCursor.fetch().reverse(); // Should use observechnage to avoid over computation ?
    for (var i = messages.length - 1; i >= 0; i--) {
      var user =  Meteor.users.findOne(messages[i].author);
      if (user) {
        messages[i].name = user.profile.name;
      }
      else {
        messages[i].name = "Unknown";
      }
    };
    var conversations = [];
    var newConversation = messages[0];
    for (var i = 0; i <= messages.length - 2; i++) {
      var timedelta = messages[i+1].timestamp - messages[i].timestamp; 
      var sameauthor = (messages[i+1].author === messages[i].author);
      if (timedelta <= 30000 && sameauthor) {
        newConversation.message = newConversation.message + " 'n" + messages[i+1].message;
      }
      else {
        conversations.push(newConversation);
        newConversation = messages[i+1];
      }
    };
    conversations.push(newConversation);
    // title bar alert 
    $.titleAlert("New chat message!", {requireBlur: true});
    return conversations;
  };

  Template.chat.events(okCancelEvents(
      '#messageInput',
      {
        ok: function (value, evt) {
          Messages.insert({
            author: Meteor.userId(),
            message: value,
            timestamp: (new Date()).getTime(),
            channel: Session.get('channel') 
          });
          evt.target.value = "";
        }
      }
  ));
  //////////// End Chat ///////////////

  //////////// Name ///////////////
  Template.participants.name = function () {
    Meteor.users.findOne(userId)
    var user = Meteor.users.findOne(Meteor.userId());
    if (user){
      Session.set('name', user.profile.name);
    }
    return Session.get('name');
  };
  Template.participants.participants = function() {
    var labelClass = function(id) { // Certainly not the right way to do it...
      if (id === Meteor.userId()) {
        return "#428bca";
      }
      var user = Meteor.users.findOne(id);
      if (user) {
        if (user.status.online) {
          return "#5cb85c";
        }
        else {
          return "#f0ad4e";
        }
      }
      else {
        return '#d9534f';
      }
    };
    var participants = Meteor.users.find({}).fetch();
    for (var i = participants.length - 1; i >= 0; i--) {
      participants[i].labelClass = labelClass(participants[i]._id);
    };
    return participants;
  }
  Template.participants.events(okCancelEvents(
    '#nameInput',
    {
      ok: function (value, evt) {
        if (value) {
          var user = Meteor.users.findOne(Meteor.userId());
          if (user){
            Meteor.users.update({_id:Meteor.userId()}, {$set:{"profile.name": value}})
          }
          Session.set('name', value);
        } 
      }
    }));
    //////////// End Name ///////////////

    //////////// Homepage ///////////////
    Template.homepage.events(okCancelEvents(
      '#channelInput',
      {
        ok: function (value, evt) {
          if (value) {
            Session.set('channel', value);
          }
        }
      }));
    Template.homepage.channel = function () {
      return Session.get('channel');
    };
    Template.homepage.channels = function() {
      return Channels.find({}, {limit:42});
    }
    Template.homepage.events({
      'click #channelButton': function (event, template) {
        Router.go('/c/'+Session.get('channel'));
      }
    });

    //////////// END Homepage ///////////

    //////////// Routing ///////////////
  Router.configure({
    layoutTemplate: 'layout'
  });
  Router.map(function () {
    this.route('channel', {
      path: '/c/:channel',
      template: 'channel',
      layoutTemplate: 'layout',
        waitOn: function () {
          Session.set('channel', this.params.channel);
          // Subscribe
          Meteor.subscribe("chatroomMessages", this.params.channel);
          Meteor.subscribe("channels", this.params.channel);
        },
        data: function() {
          var channel = Channels.findOne({name: this.params.channel});
          var participants = [Meteor.userId()]; // default;
          if (channel) {
            var participants  = channel.participants;
          }
          Meteor.subscribe("users", participants);
        }
    });
    this.route('home', {
      path: '/',
      template: 'homepage',
      layoutTemplate: 'layout',
      data: function() {
        Meteor.subscribe("channelslist");
      }
    });
  });
    //////////// END Routing ///////////

}


if (Meteor.isServer) {
  Meteor.startup(function () {
    Messages = new Meteor.Collection('messages');
    Channels = new Meteor.Collection('channels');
    // code to run on server at startup
  });
  Meteor.publish("channelslist", function() {
    return Channels.find({});
  });
  Meteor.publish("channels", function (channel) {
    var id;
    if (Channels.findOne({name:channel}) == null) {
      id = Channels.insert({
        name : channel,
        created_timestamp : (new Date()).getTime(),
        created_author: this.userId,
        participants: [],
        message : 0
      });
    } else {
      id = Channels.findOne({name:channel})._id;
    }
    if (id) {
      Channels.update({_id: id}, {$addToSet: { participants: this.userId}});
    }
    return Channels.find({});
  });

  Meteor.publish("users", function (listUsers) {
    return Meteor.users.find({_id: {$in: listUsers}});
  });

  Meteor.publish("chatroomMessages", function (channel) {
    return Messages.find({channel: channel}, {sort:{timestamp:-1}, limit:42});   
  });

}

以防万一。。。这是CSS:

/* CSS declarations go here */
@media (min-width: 1200px) {
    [class*="span"] {
        margin-left: 20px; /* correction ??? */
    }
}
body {
    background-color: #e7e7e7;
}
.chat {
    height: 100vh; /* What is that ? */
    background-color: #fff;
    -webkit-box-shadow: 0px 3px 5px 0px rgba(0, 0, 0, 0.61);
    -moz-box-shadow:    0px 3px 5px 0px rgba(0, 0, 0, 0.61);
    box-shadow:         0px 3px 5px 0px rgba(0, 0, 0, 0.61);
}
.conversation {
    height: calc(100% - 50px); /* Use preprocessing to get a fixed .conversationInput-height */
    overflow-x:hidden;
    overflow-y: auto;
}
.conversationInput {
    background-color: #ccf;
    height: 50px;
    bottom: 0;
}

/* CSS chat 'stolen' from  http://jsfiddle.net/anuradhabajpai/x8C8S/10/ */
.commentArea {
    font: 14px Arial;
    padding: 0 10px 0px;
}
.bubbledLeft,.bubbledRight {
    margin-top: 10px;
    margin-bottom: 10px;
    padding: 5px 9px;
    max-width: 80%;
    clear: both;
    position: relative;
}
.bubbledLeft{
    float: left;
    margin-right: auto;
    -webkit-border-radius: 8px 8px 8px 0px;
    -moz-border-radius: 8px 8px 8px 0px;
    -o-border-radius: 8px 8px 8px 0px;
    -ms-border-radius: 8px 8px 8px 0px;
    border-radius: 8px 8px 8px 0px;
    background-color: #65B045;
    color: #ffffff;
}
.bubbledLeft:before {
    border-bottom: 10px solid #65B045;
    border-left: 9px solid rgba(0, 0, 0, 0);
    position: absolute;
    bottom: 0;
    left: -8px;
    content: "";
}
.bubbledRight{
    float: right;
    margin-left: auto;
    text-align: right;
    -webkit-border-radius: 8px 8px 0px 8px;
    -moz-border-radius: 8px 8px 0px 8px;
    -o-border-radius: 8px 8px 0px 8px;
    -ms-border-radius: 8px 8px 0px 8px;
    border-radius: 8px 8px 0px 8px;
    background-color: #07D;
    color: white;
}
.bubbledRight:before {
    border-bottom: 9px solid #07D;
    border-right: 9px solid rgba(0, 0, 0, 0);
    position: absolute;
    bottom: 0;
    right: -8px;
    content: "";
}
.author {
    opacity: .5;
    font-size: .9em;
}
/* END CSS Chat */
#messageInput {
    width: 100%;
    padding: 0px;
    padding-left: 16px;
    height: 100%;
    border-bottom: 0;
    border-radius: 0;
}
.color-swatch {
    width: 12px;
    height: 12px;
    display: inline-block;
    border-radius: 50%;
}
body {
    font-family: 'Roboto', sans-serif;
}
.landing {
    padding-top: 150px;
    text-align: center;
}
.channels {
    padding: 10px 10px 10px 10px;
}
h1 {
    text-decoration: none;
    text-decoration-color: none;
    color: #333;
}
.header h1 {
    text-align: center;
} 

这里还有我使用的包列表:

meteor-platform
autopublish
insecure
mrt:moment
ostrio:user-status
accounts-base
accounts-password
artwells:accounts-guest
mizzao:accounts-testing
fortawesome:fontawesome
iron:router
twbs:bootstrap
meteorhacks:fast-render
peerlibrary:related
standard-app-packages

再次感谢您的帮助!

可能根本不是唯一的原因,但在var participants = Meteor.users.find({}).fetch();中,fetch()不应该存在。。。

这些线路也是如此:

var messagesCursor = Messages.find({}, {sort:{timestamp:-1}, limit:42});
var messages = messagesCursor.fetch().reverse();

我也是meter和mongodb的新手,但您的代码中只有两个fetch(),而且都有问题。。。由于我没有在mongdb上看到过,我发现这很可能是你的问题。

编辑:

此外,您使用的Meteor.users.findOne(id)应该是Meteor.users.findOne({_id:id})。与Meteor.users.findOne(messages[i].author); 相同