Hola gente,
vamos a desarrollar un chat utilizando Meteor.js
Soy consciente que existen varios ejemplos sobre esto en la web, éste es uno más.
Me he propuesto realizar un chat minimalista que sirva como base para practicar.
Lo sobresaliente de este ejemplo es el poco código que posee.
Iniciamos el proyecto:
mrt create magmchat
cd magmchat
rm magmchat.*
mkdir client server public
Agregamos los paquetes que utilizaremos:
meteor add bootstrap
meteor add accounts-ui
meteor add accounts-base
meteor add accounts-password
Esquema de la página:
A continuación un esquema simple de como se verá la página, es buena práctica definir estos esquemas antes de comenzar a trabajar, luego se simplifica la tarea.
Implementación del esquema:
Archivo: client/magmchat.html
<head></head>
<body>
<div class="navbar navbar-static-top">
<div class="navbar-inner">
<a class="brand" href="https://blog.magm.com.ar" target="_blank">Magm's Chat</a>
<ul class="nav navbar-nav pull-right">
<li><a href="#">{{loginButtons align="right"}}</a></li>
</ul>
</div>
</div>
{{> inicio}}
</body>
El código anterior define la barra de navegación y la posición de widget {{loginButtons}}, al final se renderizará la plantilla {{> inicio}}, en la cual se definirá el resto de la página.
<template name="inicio">
{{#if currentUser}}
<div class="row vspace">
<div class="offset4 span4 text-center">
<textarea id="texto" rows="5"></textarea>
</div>
<div class="span4">
Instrucciones:
<ul>
<li><span class="label label-success">Enter</span>=enviar texto</li>
<li><span class="label label-success">Ctrl+Enter</span>=nueva línea</li>
<li>Puede utilizar código html, por ejemplo: Hola <b>Meteor</b></li>
</ul>
</div>
</div>
<hr/>
<div class="row">
<div class="offset2 span8">
{{> chatItems}}
</div>
</div>
{{/if}}
</template>
El código anterior implementa la plantilla inicio, solo se generará contenido si hay un usuario autenticado, a eso lo determina {{#if currentUser}}. El contenido que se crea consta del área de texto con id="texto", el texto de ayuda y finalmente en una nueva fila (en la parte de abajo) se renderiza la plantilla {{> chatItems}}.
<template name="chatItems">
<ul>
{{#each entradas}}
<li class="itemchat">
<b>{{nombre}}: </b>{{{texto}}}
</li>
{{/each}}
</ul>
</template>
Finalmente la plantilla chatItems en la cual se creará una lista con el contenido del chat. Esta plantilla contiene un bucle each que itera sobre la fuente de datos entradas de la cual hablaremos en breve. La fuente de datos contiene objetos que representan las entradas de chat, cada objeto posee la siguiente estructura:
{
nombre: 'usuario',
texto: 'texto de chat',
timestamp: estampaDeTiempoDeLaEntrada
}
Puede observarse que se muestra el nombre en negrita <b>{{nombre}}: </b> y luego el texto está rodeado por tres llaves {{{texto}}} esto hace que si lo que se mostrará contiene código html, el browser lo interprete como tal.
Estilos personales:
Archivo: client/magmchat.css
textarea{
resize:none;
width:100%;
margin-bottom:10px;
}
.vspace {
margin-top:20px;
}
Se definen las propiedades del área de texto, lo más importante es que ocupa el 100% del espacio horizontal. Luego se crea una clase que impone un espacio de 20 pixeles al objeto al que se le asigne, en nuestro caso se utiliza para crear un separador entre la barra de opciones y el área de texto.
/* para que los items vayan apareciendo en fade */
.itemchat{
list-style:none;
margin:0;
padding:0;
animation: fadein 1s;
-moz-animation: fadein 1s; /* Firefox */
-webkit-animation: fadein 1s; /* Safari and Chrome */
-o-animation: fadein 1s; /* Opera */
}
@keyframes fadein {
from {
opacity:0;
}
to {
opacity:1;
}
}
@-moz-keyframes fadein { /* Firefox */
from {
opacity:0;
}
to {
opacity:1;
}
}
@-webkit-keyframes fadein { /* Safari and Chrome */
from {
opacity:0;
}
to {
opacity:1;
}
}
@-o-keyframes fadein { /* Opera */
from {
opacity:0;
}
to {
opacity: 1;
}
}
Finalmente se crea una clase que permite a los items de chat aparecer de forma gradual o fadein, la cantidad de texto es para dar soporte a varios navegadores, las reglas from { opacity:0; } to { opacity:1; } definen el grado de transparencia y de opacidad de inicio y fin, en la clase se define el tiempo, que en este caso es de 1 segundo.
Definición de la Colección (la base de datos):
Archivo: /chat.js
chat = new Meteor.Collection("chat");
Con este simple código que es compartido por cliente y servidor ya que se encuentra en la carpeta raíz /, creamos una colección que Meteor se encarga de persistir y que además informar los cambios a todos los clientes para que aquellas plantillas que la utilicen se actualicen automáticamente, esto es parte de la reactividad.
El código del cliente:
Archivo: client/magmchat.js
Accounts.ui.config({
passwordSignupFields: 'USERNAME_ONLY'
});
El código anterior configura el paquete accounts para que el sistema de login requiera como datos de cuenta un usuario y su contraseña, el almacenamiento y administración es local.
Template.chatItems.entradas = function () {
return chat.find({}, {sort: {timestamp: -1}, limit: 10});
};
El código anterior define la fuente de datos entradas que se itera en la plantilla chatItems. Solo destacaré que se buscan todas las entradas sin filtro alguno y que se retornan ordenadas por estampa de tiempo descendente, solo se retornan las últimas 10 entradas.
Template.inicio.events({
"keyup #texto": function (evt, tpl) {
if (evt.ctrlKey && evt.keyCode == 13) {
$("#texto").val($("#texto").val()+"\n");
} else if (evt.keyCode == 13) {
var val=$("#texto").val();
if (val.trim().length==0) {
$("#texto").val("");
return;
}
val = val.replace(/(\r\n|\n|\r)/gm,"<br/>");
Meteor.call('enviarTexto',Meteor.user().username,val,
function (error, result) {
if (error) {
console.log(error);
}
}
);
$("#texto").val("");
}
}
});
Finalmente, la última porción de código, es la más extensa, pero no reviste complejidad. Se trata del único evento que se es observado, evento keyup de la caja de texto, si se presiona Ctrl+Enter, se agrega un retorno de carro al texto '\n' y nada más. Si solo se presiona Enter, se obtiene el texto ingresado, si se ha ingresado un texto válido, se reemplazan los caracteres de retorno de carro por la marca html que lo representa <br/>, luego se llama a un método remoto llamado enviarTexto que recibe como parámetros el nombre del usuario logueado (Meteor.user().username) y el texto. A continuación analizamos la complementación del método remoto.
El código del server:
Archivo: server/metodos.js
Meteor.startup(function () {
Meteor.methods({
enviarTexto: function (usuario, txt) {
chat.insert({
nombre: usuario,
texto: txt,
timestamp: new Date()
});
}
})
});
Como puede observarse, el método es de lo más sencillo, solo inserta en la colección un nuevo objeto con los datos que recibe como parámetros y genera un valor para la estampa de tiempo, este es el motivo principal por el cual se implementa el método en el server, para que la estampa de tiempo sea coherente y no dependa de los valores de tiempo de cada cliente.
Así es como ve:
Conclusión
Eso es todo, con poco código hemos creado un char totalmente funcional, el poder de Meteor para abstraernos de problemas de sincronización y comunicaciones en tiempo real es realmente impresionante.
Pueden descargarse el código fuente desde: https://github.com/magm3333/magmchat
Pueden probarlo en funcionamiento en: magmchat.meteor.com
Espero les sea de utilidad
Hola, mira que no se como
Subido por Enzo (no verificado) el 5 Diciembre, 2013 - 01:01
Hola, gracias por tu
Subido por magm el 6 Diciembre, 2013 - 21:02
Hola, gracias por tu comentario.
Respecto a streams, en la última versión de meteor, funciona muy bien.
Este es un simple chat con estado, pero si quieres algo sin estado, streams es la respuesta más adecuada.
Saludos
Mariano
Excelente tutorial, gracias
Subido por Mikemi11 (no verificado) el 11 Diciembre, 2013 - 18:53
Hola, mrt es un wrapper de
Subido por magm el 12 Diciembre, 2013 - 18:51
Hola,
mrt es un wrapper de meteor, aumenta la funcionalidad y te permite utilizar los smart packages, o sea los paquetes publicados en atmosphere. Para agregar la fecha solo debes modificar el template, por ejemplo:
({{timestamp}}) <b>{{nombre}}: </b>{{{texto}}}
Saludos
Mariano
Gracias por el tutorial, me
Subido por miguelfausto (no verificado) el 25 Febrero, 2014 - 09:03
Gracias por el tutorial, me sirvió de mucho. Tengo una consulta de la carga de las plantillas: al iniciar la aplicación y como todavía no me eh logeado::
1- la plantilla inicio ya se cargo o descargo al cliente?
2- como puedo tener varias vistas en la misma aplicación, digamos una vista con un login personalizado y otra vista con el chat.
Gracias de antemano.
Estimado, me alegro que te
Subido por magm el 25 Febrero, 2014 - 14:09
En respuesta a Gracias por el tutorial, me por miguelfausto (no verificado)
Estimado, me alegro que te haya servido.
Las preguntas que haces son no triviales para contestarlas en un par de líneas, te recomiendo hacer lecturas más profundas sobre el tema.
-Comienza por: http://docs.meteor.com/
-Tienes un libro excelente: https://www.discovermeteor.com/ que actualmente tiene disponible la decarga del capítulo 3 que trata el tema Templates.
Como si lo anterior fuera poco aquí tienes un post sobre recursos de Meteor: http://yauh.de/articles/376/best-learning-resources-for-meteorjs
Saludos
Mariano