How to transfer data between server and client using Node and Angular? - angularjs

I have an application built with Node.js, Express, Firebase 3.4.0, and Angular.js. On the server side in server.js, I initialize the app and then get the db reference to users:
var express = require('express');
var bodyParser = require('body-parser');
var path = require('path');
var firebase = require("firebase");
var app = express();
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
app.use(express.static(path.resolve(__dirname, 'views')));
// Firebase setup; this is where it messes up...
firebase.initializeApp({
apiKey: "apiKey",
authDomain: "projectId.firebaseapp.com",
databaseURL: "https://databaseName.firebaseio.com",
storageBucket: "bucket.appspot.com"
});
var db = firebase.database().ref();
var users = db.child('users');
app.listen(process.env.PORT, process.env.IP);
app.get('/', function (req, res) {
res.sendfile('/views/index.html');
// missing a statement to pass users to the view
});
Now, this users reference needs to be passed to index.html, preferably as an array, so that data will be manipulated and rendered in the view.
Is it possible to accomplish this given that I will be using Angular?
I understand that a templating language would be handy, but since both the server and the client sides speak the same language, isn't there an easy and elegant way for them to just communicate data?
What's a standard approach to such a problem? The connection to the database must be opened on the server side, so there should be a way, in fact many ways, to transfer that data to the client side for further manipulation/decomposition
Thanks!

At first, the index.html is delivered with no business data, just instanciating your AngularJS app on the client when the DOM is ready.
Then a dedicated Angular service for dealing with Users triggers.
This service asks the server for a JSON payload through the use of $http GET request.
On the server side you handle this request with a new route :
app.get('/users', function (res, req) {
// send the users as JSON
})
When Angular receives a valid response, it then has the users and can choose to render them to HTML in a controller
This round trip can seems wasteful but it has the advantage to be autonomous, so you can reuse this dialog many times during the life of your application.
If you prefer to prepopulate the users on the / route. You need to use a server side templating engine so you can inject a <script></script> in your index.html containing some kind of global var with the initial state of your client app:
<script>window.__INITIAL_STATE__ = { users: … };</script>
This naming is arbitrary, it's just a convention of your choice, so Angular will know to check this first when it boots.

Related

How to use the SalesForce API?

I'm trying to use an express/node application to make an api call to the salesforce api and return me data according to the records I have with the account.
But it is returning this:
[{"errorCode":"NOT_FOUND","message":"The requested resource does not exist"}]
Currently my code looks like this
const express = require('express')
const app = express();
var request = require('request');
app.get('/',(req,res, next) =>{
request({
url: 'https://nav4.lightning.force.com/services/data"',
}).pipe(res);
});
})
const port = process.env.PORT || 3000; app.listen(3000, ()=>
console.log(`listening on port ${port}`))
I think my URL is wrong and might need authentication also.
You do need to authenticate first to https://login.salesforce.com. I would suggest reading and following the documentation at their documentation. The username password flow is only recommended for testing purposes though, so once you get it working you might want to look into a different oauth flow if you are building a real application depending on your use case.
For consume the Salesforce API below are the Details to notes.
Find which api to consume REST OR SOAP
Needs :
Base URL
Endpoint URL
Consumer Key and secret key
This are the Point To archive
Below are for Your Reference
https://developer.salesforce.com/page/Consuming_Force.com_SOAP_and_REST_Web_Services_from_.NET_Applications
https://trailhead.salesforce.com/content/learn/modules/apex_integration_services

server sends raw json and can't be processed by angular

I'm trying to access the data from server to $scope.resp but only raw json is getting displayed on the page.
here is the routes/addr.js
router.get('/', function(req, res) {
var pers = [{add: "abc"},{add: "pqr"}]
res.json(pers)
});
})
aj.js:
var app = angular.module('addbook', [])
app.controller('listcontroller', function($scope, $http){
$http.get('/list').then(function(response) {
$scope.resp = response
})
})
There is no error on chrome console. I notice that when $http.get request is commented out it still displays raw json. I saw a similar question where they asked to do do stringify but it is not working.
After our discussion in chat, we discovered that the issue was with your Express routes.
Angular is a client framework, which does not perform full page reloads. The user does not navigate directly to the URL on the server that is serving the data, they navigate to a URL that doesn't exist on the server, which is directed to the index.html file, where Angular is able to perform an AJAX request to retrieve the data from the Server URL and dynamically redraw the page.
If your user navigates to the server route that is serving the RAW JSON, the browser will receive the JSON and display it without any templating, styling, or other page elements. Therefore, your server URLs and your client URLs need to be different, and your server should use URLs that are exclusively identified as API urls. many people prepend /api/ to these URLs to avoid confusion, or secure them so that clients can't request them directly.
if you get a pure Json try to convert like this
$scope.resp = JSON.parse(response.data);

Express Server, calling state.go and running a method in Controller

I am currently running an express server express.js with an angular js app. I use the UI router https://github.com/angular-ui/ui-router with stateprovider and state.go.
I have a requirement to allow a url to be typed in the browser
/getEmployeeDetails/1234
Am i going along the right lines , in that the following code can be added to the express server.js to achieve this or should I be handling this in the angular app states.
app.get('/p/:empId', function(req, res) {
controller.getEmpDetaails(req.params.empId);
state.go("employeeDetailsview")
});
I am not sure what was the reason for writing angular code inside your Express server but you should really separate your client code from your server code.
I assume you are trying to get some employee details by ID from your server.
The way it is usually done is by sending a HTTP request with the ID number from your client to the server. Then, the server will process the HTTP request (Maybe get some data from the database) and return a HTTP response to the client. And then the client will process the response and do something with it.
In your client yo can do something like this:
$http.post('SERVER_URL/getEmployeeDetails/', {'id': 1234})
.then(function(response){
// Response.data will have the data returned from the server
// Do something with it. for example, go to other state and pass the data to it
state.go("employeeDetailsview", {'employee': response.data});
});
The above will request an employee with id 1234 and do something with it.
In the server side:
app.post('getEmployeeDetails/', function(req, res) {
var employeeId = req.body.id; // YOU SHOULD USE THE BODY-PARSER MODULE IN ORDER FOR THIS TO WORK.
....
// Do something with ID
....
// Return some data to the client - for example an employee object
res.status(200).json({'data': employeeObject});
});

Best practice building login for Node.js using socket.io and express

I built an app with node.js server using express 4.12.4 and socket.io. Now I have some socket-events that should be restricted only to the admin user. Since there are tons of plugins and possibilities I'm little confused. Unfortunately all the examples I found where outdated. So if somebody may provide a minimal example it would make me really happy!
FYI: The admin frontend is based on angularjs.
This can be done easily with Passport and Passport.SocketIO.
With Passport you want to authenticate the users, or at least your admin user, and set appropriate flag like user.admin = true
Then with passport.socketio which enables you to get the same user object in socket connection, you can easily verify whether the user is your admin user or not, and set appropriate listeners/emitters.
io.on('connection', function(socket){
var user = socket.request.user; // with passport.socketio
if(user.admin) {...}
});
More details on how to set it all up:
Passport allows you to authenticate a user. That usually requires the client to either register with an ID/password or over OAuth through google/facebook etc.
If the client doesn't (yet) chooses to, or you simply don't want registration process, but still want a user, what you want to do is create and login a randomly generated user.
app.use(function login(req, res, next){
if(req.user) return next(); // user already present.
var user = new User(/*randomness*/); // your new random user creation mechanism
req.logIn(user, next); // login the user
});
req.logIn method gives you more control to login the user than using passport.local strategy (which it itself uses internally).
Note: Your user should have an id property, which is required for de/serialization.
So now you'll have every user who first visits your site automatically logged in with a randomly generated user object. It's available as req.user in each middleware/request-handler.
Now Passport.SocketIO plugin for Socket.IO allows you access to the same user object as socket.request.user in your socket connection handler.
Your configuration should look something like this:
var io = require('socket.io').listen(server);
io.use(require('passport.socketio').authorize({
cookieParser: cookieParser,
secret: secretSauce,
store: sessionStore,
fail: function(d,m,e,accept){accept(null, false)},
}));
Note the cookieParser, secretSauce, and if you used sessionStore should be the same as those that you used in your Express app, something probably like this:
var cookieParser = require('cookie-parser');
var secretSauce = 'Your Secret Phrase';
var session = require('express-session');
var sessionStore = new require('connect-mongo')(session)({url:'mongodb://localhost/app'});
app.use(cookieParser());
app.use(session({secret: secretSauce, store: sessionStore, saveUninitialized: true, resave: true}));
With all that set up, you now have access to the same user object in both your Express middlewares and your Socket.IO connection handler.
io.on('connection', function(socket) {
var user = socket.request.user;
});

Enable pushState without hash using backbone and express-handlebars

I am using https://github.com/shorttompkins/benm and I want to implement pushState without using a hash. I have set:
Backbone.history.start({pushState: true});
Here's my server.js:
var express = require('express'),
http = require('http'),
path = require('path'),
routes = require('./app/routes'),
exphbs = require('express-handlebars'),
mongoose = require('mongoose'),
seeder = require('./app/seeder'),
app = express(),
bodyParser = require('body-parser'),
morgan = require('morgan'),
methodOverride = require('method-override'),
errorHandler = require('errorhandler');
app.set('port', process.env.PORT || 3300);
app.set('views', __dirname + '/views');
app.engine('handlebars', exphbs({
defaultLayout: 'main',
layoutsDir: app.get('views') + '/layouts'
}));
app.set('view engine', 'handlebars');
app.use(morgan('dev'));
app.use(bodyParser());
app.use(methodOverride());
routes.initialize(app, new express.Router());
// static asset routes
app.use('/', express.static(path.join(__dirname, 'public')));
app.use('/bower_components', express.static(path.join(__dirname, 'bower_components')));
// development only
if ('development' === app.get('env')) {
app.use(errorHandler());
}
//connect to the db server:
mongoose.connect('mongodb://localhost/MyApp');
mongoose.connection.on('open', function() {
console.log('Connected to Mongoose.');
// check if the db is empty, if so seed it with some contacts:
seeder.check();
});
//routes list:
routes.initialize(app);
//finally boot up the server:
http.createServer(app).listen(app.get('port'), function() {
console.log('Server up: http://localhost:' + app.get('port'));
});
And my routes.js:
var home = require('../controllers/home'),
contacts = require('../controllers/contacts');
module.exports.initialize = function(app) {
app.get('/', home.index);
app.get('/api/contacts', contacts.index);
app.get('/api/contacts/:id', contacts.getById);
app.post('/api/contacts', contacts.add);
app.delete('/api/contacts/:id', contacts.delete);
};
This works fine until I try to refresh a page with a backbone route eg. http://localhost:3300/add then the route is not found and I get an error 'Cannot GET /add'.
From what I've read I need to add a catch-all route similar to:
app.get('*', function(req, res){
// serve home page
});
But I can't work how how to do this with express-handlebars.
Everything I've tried seems to stop the static content being served even though I've got the express.static routes in server.js
Anyone help would be much appreciated.
When using pushstate the browser won't request the URL added through pushState() but might do when reloading the page or restarting the useragent at that location.
From the Mozilla Developer Network:
URL — The new history entry's URL is given by this parameter. Note that the browser won't attempt to load this URL after a call to pushState(), but it might attempt to load the URL later, for instance after the user restarts the browser. [...]
https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history#The_pushState%28%29_method
This applies to all user agents.
The idea of pushstate is, to store state objects for an URL while not requesting that document. However, when the user agent is requested to load that URL after the previous browsing session was destroyed, the server needs to be able to serve that URL. Note that a user might also bookmark or send the URL via e-mail to another person.
Your server and client should be able to initialize the application state accoring to that URL.
Since you said, you
prefer to have standard URLs and reserve the hash for drilling into view content likes tabs, ids, etc.
your best option seems to be to implement routes in your backend. All routes "generated" in your frontend should be served. Your single page application document needs to be served for any of those URLs.
If your application should initialize/start at the correct point, you need to either
pass the current state information from your backend to the client side application
recover the state from the URL at which the application was started on the client side
Given the current route /contacts/24552,
For option 1: you could, for example, handle the route, gather the contact data for 24552 and serve the single page application document with that contact data inlined.
For option 2: you could serve the single page application document as is for any route (except the API routes), examine the URL clientside and do the request client side. For example, you could parse location.pathname, extract relevant information (e.g. "contacts" and the ID) and either directly call the route handler or navigate to an unhandled route and back to the route /contacts/24552 to trigger the route handler.
Note: you may also use hash based URLs when using anchors in your content. You may generate those anchor names (IDs) and prefix them with the current application state route. Your Backbone route handlers have to ignore those anchor names.

Resources