diff --git a/README.md b/README.md
index af5a884..76a6c87 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,44 @@
-#Angularjs in Meteor
-##How to use it
-The angularjs app is always called meteorapp.
+# Angularjs in Meteor
+
+## Configuration
+
+The angular HTML page will be served by meteor. The page generation can be configured in the `server.js` file. The `angularAppConfig` object is used by default:
+
+ var angularAppConfig = {
+ name: 'meteorapp',
+ appController: 'AppCtrl',
+ template: {
+ placeholderElement: '
',
+ name: 'angular.html',
+ locations: ['bundle/static/', 'public/'],
+ }
+
+* `name` - name of the Angular app (used for `ng-app` attribute and name of app module, default: `'meteorapp'`)
+* appController - name used to define the main controller on the body element (default: `'AppCtrl'`)
+* template - config options for how to load and insert the Angular template
+
+### Angular template config options
+
+* `placeholderElement` - the tag element to substitute with the template (default: `''`')
+* `name` - the name of the template file (default: `'angular.html'`)
+* `locations` - relative folder locations to search for the Angular template.
+
+Note that `locations` are set up to first try in the expected "deploy" location, then the development location.
+
+If you define a config file `angularAppConfig.json`, it will be used for angular app configuration. Here an example of a custom config file:
+
+ {
+ name: 'my-meteorapp',
+ appController: 'AppController',
+ template: {
+ placeholderElement: '
',
+ name: 'main-view.html',
+ locations: ['bundle/static/', 'public/'],
+ }
+
+## Configuring the Angular app
+
+Define the main angular module, named to match the config Angular app name config setting for the meteor server (default: `'meteorapp'`):
angular.module('meteorapp', []).
config(['$routeProvider', function($routeProvider) {
@@ -8,13 +46,55 @@ The angularjs app is always called meteorapp.
when('/index', {templateUrl: 'partials/index.html', controller: MeteorCtrl}).
otherwise({redirectTo: '/'});
}]);
-###Directory structure
+
+For a complete example, see [meteor-angular-leaderboard](https://github.com/bevanhunt/meteor-angular-leaderboard)
+
+ # coffeescript example
+
+ angular.module('meteorapp', [])
+ .config ['$routeProvider', '$locationProvider', ($routeProvider, $locationProvider) ->
+ $locationProvider.html5Mode(true)
+ $routeProvider.when '/'
+ controller: 'home'
+]
+
+
+### Directory structure
+
+Create the angular template file with a name and location matching your server config settings.
+
+Default structure:
/public
/partials
angular.html(Main screen should contain body content)
-###Usage
+Custom structure:
+
+ /public
+ /partials
+ /angular
+ main-view.html(Main screen should contain body content)
+
+The router should load the index file when you navigate to root `'/'` of your app. The index file will then be served by meteor (see server.js)
+
+Example 'index.html' file
+
+ /client
+ index.html
+
+Example index HTML file
+
+
+ Leaderboard
+
+
+Meteor server will magically create the `` and `` element.
+
+###Usage of $meteor
+
+You can simply inject the $meteor module provided anywhere you want to use it, typically in your meteor-enabled controllers. Then execute the provided Meteor commands (see client.js)
+
app.controller('MeteorCtrl', ['$scope','$meteor',function($scope,$meteor){
$scope.todos = $meteor("todos").find({});
$meteor("todos").insert({
@@ -28,6 +108,49 @@ The angularjs app is always called meteorapp.
-###Deploying
-Make sure that you always write angularjs code that can be minified, else use the --debug function. To deploy with Heroku use this buildpack. Thanks to @mimah
+
+### Current user
+
+In order to add Meteor current user functionality:
+
+See [current user issue #18](https://github.com/lvbreda/Meteor_angularjs/issues/18)
+
+You can use something like:
+
+ app.directive('currentUser', function($timeout) {
+ return function(scope, element) {
+ var timeoutId; // timeoutId, so that we can cancel the user updates
+ // used to update the UI
+ function updateUser() {
+ element.text((Meteor.user() != null)? Meteor.user()._id : "anonymous");
+ }
+ // schedule update in one tenth of a second
+ function updateLater() {
+ // save the timeoutId for canceling
+ timeoutId = $timeout(function() {
+ updateUser(); // update DOM
+ updateLater(); // schedule another update
+ }, 100);
+ }
+ // listen on DOM destroy (removal) event, and cancel the next UI update
+ // to prevent updating user after the DOM element was removed.
+ element.bind('$destroy', function() {
+ $timeout.cancel(timeoutId);
+ });
+ updateLater(); // kick off the UI update process.
+ }
+ });
+
+The `currentUser` directive is by default a HTML element attribute.
+
+
+
+Then in a controller:
+
+ $scope.currentUser = $meteor('users').find({_id:Meteor.userId()})
+
+### Deploying
+
+Make sure that you always write angularjs code that can be minified, else use the `--debug` function. To deploy with Heroku use this buildpack. Thanks to @mimah
+
https://github.com/mimah/heroku-buildpack-meteorite
diff --git a/client.js b/client.js
index 8c5acb7..fa4b899 100644
--- a/client.js
+++ b/client.js
@@ -3,6 +3,10 @@ function() {
var self = this;
self.collections = {};
self.getCollection = function(name) {
+ if(name == 'users'){
+ return Meteor.users;
+ }
+
if (self.collections[name]) {
return self.collections[name];
} else {
diff --git a/server.js b/server.js
index 76eaaba..3191cb2 100644
--- a/server.js
+++ b/server.js
@@ -3,44 +3,117 @@ var fs = Npm.require("fs");
var path = Npm.require("path");
var Fiber = Npm.require("fibers");
+
+// default config
+var angularAppConfig = {
+ name: 'meteorapp',
+ appController: 'AppCtrl',
+ template: {
+ placeholderElement: "",
+ name: 'angular.html',
+ locations: ['bundle/static/', 'public/'],
+ notice: "This is used as your main page, this should contain the contents of the body.",
+ }
+}
+
+angularAppConfig.template.resolvedPaths = function() {
+ var self = this;
+ var resolved = [];
+ for (var path in this.paths) {
+ paths.push(path + self.name);
+ }
+ return resolved;
+}
+
+var appConfig = {
+ readFile: function(filePath) {
+ new String(fs.readFileSync(path.resolve(filePath)));
+ },
+ getAppHtml: function() {
+ try {
+ return this.readFile('bundle/app.html');
+ } catch(e) {
+ return this.readFile('.meteor/local/build/app.html');
+ }
+ },
+
+ getAngularTemplate: function() {
+ var templatePaths = angularApp.template.locations;
+
+ // iterate all templatePaths and try each
+ for (var templatePath in templatePaths)
+ // only attempt read if file exists
+ if (fs.existsSync(templatePath)
+ return this.readFile(templatePath);
+ }
+ console.log("Angularjs\n______\nCreate any of: " + templatePaths.join(', ') + "\n " + angularApp.template.notice);
+ },
+ replaceCode: function() {
+ var element = function(tag) {
+ return "<" + tag + " ";
+ }
+ var ngAttr = function(name, value) {
+ return " ng-" + name + "='" + value + "' ";
+ }
+
+ var loadAngularAppConfig = function() {
+ if (fs.existsSync('angularAppConfig.json')) {
+ try {
+ angularApp = JSON.parse(this.readFile('angularAppConfig.json'));
+ } catch (e) {
+ console.log("Angularjs\n______\nCreate a file: 'angularAppConfig.json' to override the default settings"
+ return null;
+ }
+ }
+ }
+
+ var angularApp = loadAngularAppConfig || angularAppConfig;
+
+ angularApp.template.resolvedPaths = angularAppConfig.template.resolvedPaths;
+
+ //
+ code = appConfig.getAppHtml();
+
+ // insert Angular template
+ code = code.replace(angularApp.template.placeholderElement, appConfig.getAngularTemplate());
+
+ var htmlElem = element('html');
+ var htmlReplacement = htmlElem + ngAttr('app', angularApp.name);
+
+ // insert ng-app on html element
+ code = code.replace(htmlElem, htmlReplacement);
+
+ // TODO: Allow insert on html element?
+ // insert ng-controller="AppCtrl" on angular placeholder element
+ if (angularApp.appController) {
+ var plh = element(angularApp.template.placeholderElement);
+ var plhReplacement = plh + ngAttr('controller', angularApp.appController);
+
+ code = code.replace(plh, plhReplacement);
+ }
+
+ if (typeof __meteor_runtime_config__ !== 'undefined') {
+ code = code.replace("// ##RUNTIME_CONFIG##", this.runtimeConfig());
+ }
+ }
+
+ runtimeConfig: function() {
+ "__meteor_runtime_config__ = " + JSON.stringify(__meteor_runtime_config__) + ";");
+ }
+}
+
+
__meteor_bootstrap__.app
.use(connect.query())
.use(function (req, res, next) {
// Need to create a Fiber since we're using synchronous http calls
Fiber(function() {
- try{
- var code = fs.readFileSync(path.resolve('bundle/app.html'));
- }catch(e){
- var code = fs.readFileSync(path.resolve('.meteor/local/build/app.html'));
- }
- var angular = "";
- try{
- angular = fs.readFileSync(path.resolve('bundle/static/angular.html'));
- }catch(e){
- if(fs.existsSync("public/angular.html")){
- angular = fs.readFileSync(path.resolve('public/angular.html'));
- }else{
- console.log("Angularjs\n______\nCreate public/angular.html\n This is used as your main page, this should contain the contents of the body.");
- }
- }
-
-
- code = new String(code);
- // console.log((new String(angular)).join());
- code = code.replace("",new String(angular));
- code = code.replace("",'');
- if (typeof __meteor_runtime_config__ !== 'undefined') {
- code = code.replace(
- "// ##RUNTIME_CONFIG##",
- "__meteor_runtime_config__ = " +
- JSON.stringify(__meteor_runtime_config__) + ";");
- }
-
+ var code = appConfig.replaceCode();
+
res.writeHead(200, {'Content-Type': 'text/html'});
- res.write(code);
- res.end();
- return;
- //next();
+ res.write(code);
+ res.end();
+ return;
}).run();
});