I have been building a simple application to learn angular.js. So far I hooked up all the pieces in the MEAN stack and I am able to save and retrieve data from Mongo.
The app is essentially a todo list. The user can create a project and inside the project create "cards" with "todos" which can then be moved from state to state ("backlog", "in progress", "complete", etc.)
I would like to be able to push the notifications to all the people who are connected to tell their apps that a refresh is needed to get the latest todos. In other words, let's say that user A adds a new card to project A, I would like to send a message out to all users who are currently watching project A so that their application issues a project refresh to get the latest and greatest.
Any suggestions on how to proceed? Which technology, if any, I need to add to the MEAN stack to be able to do something like this?
Thanks in advance
Since you're on the MEAN stack, the standard recommendation in Node would be to use the Socket.IO API.
They provide the following example of two way messaging (which would facilitate your push messages very easily):
Client
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost');
socket.on('news', function (data) {
console.log(data);
socket.emit('my other event', { my: 'data' });
});
</script>
Server
var app = require('http').createServer(handler)
, io = require('socket.io').listen(app)
, fs = require('fs')
app.listen(80);
function handler (req, res) {
fs.readFile(__dirname + '/index.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
It will use websockets where possible, and fallback to AJAX long polling or Flash polling in browsers where there is no websocket support.
As for integrating with Angular, here's a good blog post on Socket.IO and Angular:
I'll be writing about how to integrate Socket.IO to add real-time
features to an AngularJS application. In this tutorial, I'm going to
walk through writing a instant messaging app.
If you're already working with Express, you should check out express.io.
It has a bunch of cool features like Session support and the ability to forward normal HTTP routes to realtime routes.
Here is a module we have written for getting AngularJS push notifications working in PhoneGap / Cordava (with full instructions):
http://www.scorchsoft.com/blog/free-angularjs-cordova-push-notification-plugin/
Simply download the example code and install. There is also code included for setting up the pushing component in PHP.
Why not with HTML5 Notification API....
export default class NotificationService {
/**
* Constructor of the class.
*
*/
constructor() {}
showPushNotification(title: string = '', message: string, iconPush) {
if (window.Notification && Notification.permission !== "denied") {
Notification.requestPermission(function(status) {
var n = new Notification(title, {
body: message,
icon: iconPush
});
});
}
}
}
Related
I'm developing a calendar application with Node.js, express.js and Sequelize.
The application is simple, you can create tasks in your calendar, but you can also assign some tasks to others users of the system
I need to create a notification system with socket.io, but I don't have experience with websockets. My big doubt is how can I make my server send a notification to the user that you assign the task?
My ports configurations is on a folder called bin/www, my express routes are defined on a file called server.js
Any Idea?
I want to introduce you to ready to use backend system that enables you to easily build modern web applications with cool functionalities:
Persisted data: store your data and perform advanced searches on it.
Real-time notifications: subscribe to fine-grained subsets of data.
User Management: login, logout and security rules are no more a burden.
With this, you can focus to your main application development.
You can look at Kuzzle, wich is one project I working on:
First, start the service:
http://docs.kuzzle.io/guide/getting-started/#running-kuzzle-automagically
Then in your calendar application you can the javascript sdk
At this point you can create a document:
const
Kuzzle = require('kuzzle-sdk'),
kuzzle = new Kuzzle('http://localhost:7512');
const filter = {
equals: {
user: 'username'
}
}
// Subscribe every changes in calendar collection containing a field `user` equals to `username`
kuzzle
.collection('calendar', 'myproject')
.subscribe(filter, function(error, result) {
// triggered each time a document is updated/created !
// Here you can display a message in your application for instance
console.log('message received from kuzzle:', result)
})
// Each time you have to create a new task in your calendar, you can create a document that represent your task and persist it with kuzzle
const task = {
date: '2017-07-19T16:07:21.520Z',
title: 'my new task',
user: 'username'
}
// Creating a document from another app will notify all subscribers
kuzzle
.collection('calendar', 'myproject')
.createDocument(task)
I think this can help you :)
Documents are served though socket.io or native websockets when available
Don't hesitate to ask question ;)
As far as I can understand you need to pass your socket.io instance to other files, right ?
var sio = require('socket.io');
var io = sio();
app.io = io;
And you simply attach it to your server in your bin/www file
var io = app.io
io.attach(server);
Or what else I like to do, is adding socket.io middleware for express
// Socket.io middleware
app.use((req, res, next) => {
req.io = io;
next();
});
So you can access it in some of your router files
req.io.emit('newMsg', {
success: true
});
The official RabbitMQ Javascript tutorials show usage of the amqp.node client library
amqp.connect('amqp://localhost', function(err, conn) {
conn.createChannel(function(err, ch) {
var q = 'hello';
ch.assertQueue(q, {durable: false});
// Note: on Node 6 Buffer.from(msg) should be used
ch.sendToQueue(q, new Buffer('Hello World!'));
console.log(" [x] Sent 'Hello World!'");
});
});
However, I find it's hard to reuse this code elsewhere. In particular, I don't know how to exports the channel object since it's in a callback. For example in my NodeJs/Express App:
app.post('/posts', (req, res) => {
-- Create a new Post
-- Publish a message saying that a new Post has been created
-- Another 'newsfeed' server consume that message and update the newsfeed table
// How do I reuse the channel 'ch' object from amqp.node here
});
Do you guys have any guidance on this one? Suggestion of other libraries is welcomed (Since I'm starting out, ease of use is what I considered the most important)
amqp.node is a low-level API set that does minimal translation from AMQP to Node.js. It's basically a driver that should be used from a more friendly API.
If you want a DIY solution, create an API that you can export from your module and manage the connection, channel and other objects from within that API file.
But I don't recommend doing it yourself. It's not easy to get things right.
I would suggest using a library like Rabbot (https://github.com/arobson/rabbot/) to handle this for you.
I've been using Rabbot for quite some time now, and I really like the way it works. It pushes the details of AMQP off to the side and lets me focus on the business value of my applications and the messaging patterns that I need, to build featurs.
As explained in the comments, you could use the module.exports to expose the newly created channel. Of course this will be overridden each time you create a new channel, unless you want to keep an array of channels or some other data structure.
Assuming this is in a script called channelCreator.js:
amqp.connect('amqp://localhost', function(err, conn) {
conn.createChannel(function(err, ch) {
var q = 'hello';
ch.assertQueue(q, {durable: false});
//this is where you can export the channel object
module.exports.channel = ch;
//moved the sending-code to some 'external script'
});
});
In the script where you may want to use the "exported" channel:
var channelCreator = require("<path>/channelCreator.js");
//this is where you can access the channel object:
if(channelCreator.channel){
channelCreator.channel.sendToQueue('QueueName', new Buffer('This is Some Message.'));
console.log(" [x] Sent 'Message'");
}
Hope this helps.
I am developing a web app using the MEAN stack. On my Node server I have a POST route - /api/gps to which a remote device keeps posting GPS data regularly with an interval of 10 seconds or so. I service this POST request by taking the post body and saving the details such as timestamp, tripid, latitude, longitude etc to my MonngoDB collection.
Now here is where I am stuck -
I have a route - /displaymap which is rendered by displaymap.jade and associated with a controller - MapDisplayCtrl. Here I have to display the map of the most recently posted GPS data from the device. So how do I update the map as soon as I get new POST data to /api/gps?
app.js file
var GPSData = mongoose.model('GPSData', gpsSchema);
app.post('/api/particle', function(req, res) {
GPSData.create({
tripid : req.body.tripId,
latitude: req.body.latitude,
longitude: req.body.longitude,
timestamp: Date.now()
}, function(err, doc) {
if(err) {
res.send(err);
} else {
res.send(doc);
//here is where I want to publish an event say, 'SendMapData'
//that sends co-ordinates to the controller
}
});
});
MapDisplayCtrl.js file
var myApp = angular.module('myapp');
myApp.controller('MapDisplayCtrl', function($http, $scope) {
//listen to the 'SendMapData' event and get the co-ordinates
//draw a google map using the co-ordinates
});
I guess all I need is an event emitter at NodeJS side and a listener at AngularJS side, but I don't know how to implement it. I hope I've give enough information for you to answer. If you need anymore info i'll provide it. Thanks in advance!
You can use socket.io to communicate in real time between server & client.
Server:
//here is where I want to publish an event say, 'SendMapData'
//that sends co-ordinates to the controller
socket.emit('SendMapData', data);
Controller:
//listen to the 'SendMapData' event and get the co-ordinates
//draw a google map using the co-ordinates
socket.on('SendMapData', function(serverData) {
//do what you want with data received from server.
});
For docs check socket.io (not the best documentation, but it helps)
EDIT
In order to use socket.io inside an angular app, to be "the angular way" I have build a service for this (not all by myself, inspired by SO):
MYAPP.factory('socket', ['$timeout', function($timeout){
var socketMethods = {},
socketio;
//fn: connect
//desc: connect to server
socketMethods.connect = function(server){
if( ! angular.isUndefined(socketio)) return;
var ioUrl = 'ws://'+ server.fullAddr;
var ioManager = {transports: ['websocket', 'polling'], reconnectionAttempts: Infinity};
socketio = io(ioUrl, ioManager);
}
//fn: on
//desc: receive data from server
socketMethods.on = function(eventName, callback){
//check if event is already registered; 'connect' registered by default, ignore it.
if(socketio.hasListeners(eventName) && eventName != 'connect') return;
socketio.on(eventName, function(serverData, respondToServer){
$timeout(function(){
callback.call(socketio, serverData, respondToServer);
});
});
}
//fn: emit
//desc: send data to server
socketMethods.emit = function(eventName, data, callback){
socketio.emit(eventName, data, function(serverResponse){
$timeout(function(){
if(callback) callback.call(socketio, serverResponse);
});
});
}
return socketMethods;
}]);
...and you can inject 'socket' in your controller, open a socket connection and listen/emit events.
I am taking a look at Node.js and thinking about using it for building an API. From what I can tell, ExpressJS would be the web framework and is not what I'd be looking for to solve this.
So what would a web service look like? Would it simply be creating a server, talking to mongo and returning results? Also, what does routing look like? (I'd obviously want to 'design' the routes).
If Express would be your web framework, look at the express-resource (Github) middleware for routing an API. You define resources and it'll wire up REST-style routing for you with very little boilerplate.
app.resource('horses', require('./routes/horses'), { format: json })
Given the above, express-resource will hook up all the REST-style routes to actions you supply, returning JSON by default. In routes/horses.js, you export actions for that resource, along the lines of:
exports.index = function index (req, res) {
// GET http://yourdomain.com/horses
res.send( MyHorseModel.getAll() )
}
exports.show = function show (req, res) {
// GET http://yourdomain.com/horses/seabiscuit
res.send( MyHorseModel.get(req.params.horse) )
}
exports.create = function create (req, res) {
// PUT http://yourdomain.com/horses
if (app.user.canWrite) {
MyHorseModel.put(req.body, function (ok) { res.send(ok) })
}
}
// ... etc
You can respond with different representations:
exports.show = {
json: function (req, res) {
// GET http://yourdomain/horses/seabiscuit.json
}
, xml: function (req, res) {
// GET http://yourdomain/horses/seabiscuit.xml
}
}
Middlewares like express-resource can make life with Node and Express much easier, take a look through the examples on github to see if it'll do what you need.
Here is a stub that looks up a horse name from a Postgres database and returns the result as JSON. Clients would access would access the API by going to address such as http://yourdomain.com/api/horse/seabiscuit
app.get('/api/horse/:name', function(req, res){
pg.connect(conString, function(err, client) {
var horse = req.params.name;
var sql = "...";
client.query(sql, function(err, result) {
if (err) {
...
}
for (var i=0; i<result.rows.length; i++) {
// Customize data as needed
}
return res.send(JSON.stringify(result.rows));
});
});
});
Node is pretty low level. It's like C in JavaScript's clothing. Since it's comparable to C, there's pretty much a lot you can do with Node. Creating web servers is just one of them. You can create live chat servers using sockets, blogs, streaming etc. The possibilities are infinite. You are limited only by your imagination.
Routing is just a task where you take in commands (commonly via URL or headers) and do tasks based on those commands passed.
But even I have not yet scathed the surface of node. It's API is huge and getting bigger. Better try using some basic library like Express or Connect first since they pretty much abstract the basic requirement of building the server from code.
I am working on a node.js project that I am leveraging Socket.IO in, and am having an issue getting my head around a scoping issue. Here is what I am trying to do:
var io = require('socket.io').listen(80);
session_manager = require('./includes/session_manager');
// client joins the socket server
io.sockets.on('connection', function(client) {
client.on('X.Session.join', function(session_id, client) {
session_manager.joinSession(session_id, function(err, session) {
// do whatever
});
});
// BRING IN MORE LISTENERS/EMITTERS?
require('someModuleIBuild');
});
As you can see I am basically setting up the initial connection, joining a session via a managing class (so I know who to emit to for which session) and then I am trying to dynamically bring in some custom stuff that ALSO is going to be emitting and listening via the socket connection.
So how do I reference this current connection from within the confines of my custom modules? All the examples I have seen have all the "on" and "emit" functions in one file, which seems like it could get out of control pretty quickly.
I am possibly over-thinking/over-complicating this (this is my first node.js project, first socket-based project, first mostly-javascript project....etc) but any help would be appreciated.
create your modules like this and you can pass the client into the module
module.exports = function(client) {
client.on("whatever", function () {
});
client.on("whenever", function (data) {
});
};
and then do the require like this
require('someModuleIBuild')(client);