I'm experimenting to get an Angular.js application working with Node.js.
Currently I have the code below in the file MY-PROJECT/public/js/controllers.js
function LoginController( $scope )
{
// fetch waiters
var Waiter = require( '../models/waiter.js' );
}
LoginController.$inject = ['$scope'];
As you can see, I'm using require() to access a model file. But it seems like the require()-function is not accessible in this file / folder.
The error I get in the console when I visit the page is:
ReferenceError: require is not defined
The reason for the error is most certainly because I directly include this controllers.js-file in my HTML-file with script-tags (so the require()-function from Node.js is not available).
Now my question is: how can I access a model-file (eg. from MY-PROJECT/models/waiter.js) in the controllers.js-file?
Many thanks in advance!
RequireJS looks like it has what you need.
I was doing it all wrong. Because I'm making a 'realtime-app' (is that the correct name?) and using Socket.io, it works differently.
In the client-controller, I send a message to the server to request the data. The server fetches the data and send it back to the client.
So in the client I actually don't need to require the model, because I get the data in JSON-format from the server.
This is how I solved it, may be useful to others:
/**
* Login controller
*/
function LoginController( $scope, socket )
{
// listen to server when it sends you the cats
socket.on( 'here-are-all-the-cats', function ( cats )
{
$scope.cats = cats;
});
// send message to the server, to request the waiters
socket.emit( 'i-want-all-the-cats' );
}
WaiterController.$inject = [ '$scope', 'socket' ];
Note: I used 'cats' instead of 'waiters', just to make it more clear to others.
Related
I currently have an app which uses Express with Jade templates.
I'm building a new version of the app using Angular with client-side HTML.
I need access to certain request parameters in order to determine user permissions in my Angular code. My problem is that I don't know how to get ahold of these parameters in my Angular controllers/services.
Below is what currently occurs in Express with the Jade structure:
routes.js:
router.get('/player/:id',
playerRoute.show
);
player.js:
var show = function(req, res) {
res.render('player', {user: req.user});
};
...and now my new version's handler:
var player = function(req, res) {
//res.sendFile(path.join(__dirname, '../v2', 'index.html'));
res.json({user: req.user});
};
The correct user JSON is sent back to my client-side with the code above. When res.json is commented out and res.sendFile uncommented the correct HTML is rendered. My dilemma is how to both render this HTML AND provide my client-side Angular code with the user JSON object?
After all that, your question just boils down to:
MY dilemma is how to both render this HTML AND provide my client-side Angular code with the user JSON object?
You don't. The usual case is to just render the HTML along with the assets needed to render the initial app (hide everything, show a splash screen whatever). Further data (like getting your user) is handled by API calls to your server via Angular's HTTP facilities. That means they are separate. After that API call, your app determines what to render.
Otherwise, you could just render the data in the HTML as some global variable and have Angular pick it up from there. This is messy IMO, but doesn't require a separate API call to get the data.
copied from my own answer to a similar question
To get a variable from server to client javascript try templating a json string into the html and loading it from the javascript. EJS handles quote escaping and I think Jade does too. For reference content!= safeString tells Jade to skip escaping, so does content !{safeString}.
- var user={id:1, displayName:'foo'}
#example
meta(data-userJSON=JSON.stringify(user))
script(src="//code.jquery.com/jquery-1.11.3.min.js")
script.
var user = JSON.parse(
$('#example meta').attr('data-userJSON')
)
console.log(user);
span #{user.id}
span #{user.displayName}
Here's how I ended up handling this situation. I simply created a new API endpoint which I can easily hit with an Angular service. Here's the Node setup:
routes.js:
router.get('/currentUser',
apiController.currentUser.index
);
currentUser.js:
var index = function(req, res) {
res.json({user: req.user});
};
module.exports = {
index: index
};
Still seems odd to me to make an API call to get the request parameters, but it works. Feedback appreciated.
I had this code working before I wanted to change the client side collection find/insert methods to server side. I removed insecure and autopublish from my meteor project, and changed my code to what it is below.
My angular Code in client/controllers/item-controller.js
angular.module('prototype').controller('ItemController', ['Config','$window','$meteor', function(Config, $window, $meteor) {
this.items = function(){
Meteor.call('getAllItems', function(err, res){
alert("error: " +err + " res: " + res );
return res;
});
}
My item-collection codee in server/item-collection-methods.js
Meteor.methods({
getAllItems : function(){
console.log("i got here")
return Items.find();
}
});
My main file in lib/app.js
Items = new Mongo.Collection("Items");
Before I had 15 items showing, now none of them show.
when I copy my Meteor.call function into the chrome console, all I get back is undefined.
I have a feeling it either has to do with the project structure, or the fact that autopublish and insecure are removed. Any advice would be helpful.
EDIT:
I did get something in my server console
I20150629-00:54:54.402(-4)? Internal exception while processing message { msg: '
method', method: 'getAllItems', params: [], id: '2' } Maximum call stack si
ze exceeded undefined
Meteor data transmission works with a publish/subscribe system. This system is able to replicate part of or all the data that is stored in your MongoDB (server) to the client in an in-memory DB (MiniMongo). Autopublish was publishing everything on the client, as you removed it there is nothing in your Items collection anymore.
In order to publish some data to the client you have to declare a publication on the server side:
Meteor.publish('allItems', function () {
//collection to publish
return Items.find({});
});
And subscribe on the client (either in the router or in a template):
Meteor.subscribe('allItems');
To learn more about this system you can read the official docs.
Concerning your method "getAllItems", you cannot directly send a cursor (Items.find()) on your data, that is why you are getting the error message "Maximum call stack size exceeded".
But you could send an array of these data by returning Items.find().fetch(). Also the call to a Meteor method is asynchronous, so you have to use the callback (more on Meteor methods)
Please note that by sending data over a method (which is perfectly acceptable) you lose the reactivity offered by the publish/subscribe system.
The app I'm developing allows users to change the IP of the server (where the REST API is). This address is stored in a variable that can change, but the problem is that when the services are instantiated, the base URL cannot be changed. Following this answer I was able to change the url of some of the services, but I can't do the same for those who have POST actions.
I've tried several configurations, but there's always a problem. For example, this:
// Services file
app.factory('Bookings', BookingsFactory)
function BookingsFactory($resource, GlobalVariables) {
return $resource('http://:url/api/bookings/:id/', null, {url: '#url'});
}
//Controllers file
Bookings.save(booking, {url: GlobalVariables.IPServer});
Throws this error message "net::ERR_NAME_NOT_RESOLVED", because the request URL is not correct: "http://api/bookings/?end_time=2015-06-30T09:30&name=Reunion&room=1&start_time=2015-06-30T09:43&started=true".
If I call it like this:
//Services file
app.factory('Bookings', BookingsFactory)
function BookingsFactory($resource, GlobalVariables) {
return $resource('http://:url/api/bookings/:id/', {url: '#url'});
}
//Controllers file
Bookings.save({booking: booking, url: GlobalVariables.IPServer});
I get a 400 BAD REQUEST error, and the response asks for content for all the required fields: "This field is required."
I'm using AngularJS v1.3.13. Is there a way to change the base URL in every petition with this approach, even on POST requests? Or even better, is there a way to update the URL in every factory of the application after the app is started?
In an app that I work on I use the $rootScope to hold my base server URL for all requests. I don't know if that's a good way to use $rootScope or not, but what's for sure is that the app is working.
oops sorry I forgot to also add that I can change the base URL while the app is running, which is what you need.
I have an AngularJS application and I want to cache the REST service responses. I found some libraries like angular-cached-resource which can do this by storing the data into the local storage of the web browser.
But sometimes I do some POST / PUT / DELETE REST calls and then some of the REST previously cached service responses need to be performed again. So it seems that it is possible to delete the cached responses then and the call will be sent to the server next time.
But what about if the server sends me in HTTP Header some values like the expires or the etag? I have to read the HTTP Header and react by myself or is there a library in AngularJS which can also handle this?
So if I should hit the server and not read the cache of the local storage is dependent on the HTTP Header Cache fields and if there are any PUT / POST / DELETE calls which have the response that for example "reload of every user settings element" are needed. So I have to take this response and create a map which tells me that for example REST services A, C and F (user settings related stuff) needs to hit the server again next time when they are executed or if the Cache expires from the HTTP Headers.
Is this possible with an AngularJS library or do you have any other recommendations? I think this is similar to Observer or PubSub Pattern, isn't it?
One more thing: Is it also possible to have something like PubSub without using a cache / local storage (so also no HTTP Header Cache controls)? So I can not call the REST service, because then it would hit the server, which I do not want in some circumstances (response from a previous REST call which returns me the event "reload of every user settings element").
You can try something like this.
app.factory('requestService', ['$http', function ($http) {
var data = {};
var service = {
getCall : funtion(requstUrl, successCallback, failureCallback, getFromCache){
if(!getFromCache){
$http.get(requstUrl)
.success(function(data){
successCallback(data);
data.requstUrl = data;
})
.error(function(){
failureCallback(data);
})
}else{
successCallback(data.requstUrl);
}
},
postCall : function(requestUrl, paramToPass, successCallback, failureCallback, getFromCache){
if(!getFromCache){
$http.post(requestUrl, paramToPass)
.success(function(data){
successCallback(data);
data.requstUrl = data;
})
.error(function(data){
failureCallback(data);
})
}else{
successCallback(data.requstUrl);
}
}
};
return service;
}]);
This is just a simple code I wrote to implement your concept. I haven't tested it and is all yours.
i am building a Sencha Touch 2 Application with userspecific datasets.
Architecture of the App:
Sencha Touch App <=====> Java Server backend with REST Services
( many AJAX requests =) )
What i actually have is:
Login the user with username/password
The app gets initialized and the loginform comes into play. After submitting the form as a AJAX request, the server backend checks the userdata and calls the client callback function.
And what i want to do is:
The callback function should
create a cookie with the sessiontoken or
store the sessiontoken within the localstorage (http://docs.sencha.com/touch/2-0/#!/api/Ext.data.proxy.LocalStorage) or
store the sessiontoken within js variable
Okay, shouldn't be the problem.
But how can i achieve the following:
Most of the data is specific for one user and should be returned by the REST service if needed (by clicking on the navigation,...). How can i send the sessiontoken (see above) within every AJAX request - so the server can provide the suitable datasets (assuming the token is valid)?
Send cookies within AJAX requests
I have already read that cookies gets automaticly added to the request if the url is on the same space, right? The Java Server is on the same domain (localhost:8080) but the cookies aren't available - instead of requests on urls like 'app.json'. I thought that cross-domain-requests are really domain specific?
Send paramaters within AJAX requests
Because the cookies aren't avi i thought about the possiblity of 'manually' adding parameters to the ajax requests. The App will contain many AJAX requests and thats why i dont want to add the token manually - i tried to override the requests function of Ext.Ajax but i failed ;-( :
(function() {
var originalRequest = Ext.data.Connection.prototype.request;
Ext.override(Ext.data.Connection, {
request : function(options) {
alert("Do sth... like add params");
return originalRequest.apply(this, options);
}
});
})();
ERROR:
Uncaught Error: [ERROR][Ext.data.Connection#request] No URL specified
I also tried to add a listener
Ext.Ajax.add({
listeners : {
beforerequest : function( conn, options, eOpts ){
alert("Do sth... like add params");
}
}
});
ERROR:
Uncaught TypeError: Object [object Object] has no method 'add'
Any idea about how i can add the token?
Or any better way of handling these case?
Thanks!
Finally i successfully used:
function addAjaxInterceptor(context)
{
Ext.Ajax.on('beforerequest', function(conn, options, eOptions)
{
// add the param to options...
}, context);
}
Executed from the app (=> addAjaxInterceptor(this)).
But the following solution is more suitable for my situation i think:
Ext.Ajax._defaultHeaders = {
// params as json
};
(Cause Ext.Ajax is a singleton object and i dont change the params for every request)