How to provide configuration to AngularJS module? - angularjs

Currently I am combining a traditional application with some dynamic parts written using AngularJS. I would like to provide some configuration from my server to my module. In this case I would like to configure the application 'base' URL. All templates can be found at a specific location and this location is determined by the server.
So I tried something like this:
angularForm.config(
function($routeProvider, TemplateLocator) {
$routeProvider.when('/', {
controller : TestController,
templateUrl : TemplateLocator.getTemplate('FormOuterContainer')
});
});
At the server:
<script type="text/javascript">
angular.module('BoekingsModule.config', []).provider('TemplateLocator', function() {
this.$get = function() {
return // something
}
this.getTemplate = function(name) { return 'location...'; }
});
</script>
However, I am not sure this is the right way.
So in short: how can I provide some (external) configuration to a module without having to change the module itself?

There are several things you can do
Render the locations in the js on the server.
Pro: less requests -> better performance (usually)
Cons:
combining server side rendering with an SPA makes the system more complex, leading to higher maintenance costs.
it is harder to properly compress your js files if you want to mix in server side rendering, embedding js in html is also ugly.
Extract the template location to a service.
From this service you could use a $resource to fetch the data from the server in json format. This keeps things simpler, but it could also increase your web server's load.

Wow it has been a long time since. I completely forgot about this post.
So, in the end I decided it was better to use another approach. Like iwein said, combining SPA with server side rendering makes the application a lot more complex. Therefore I extracted the SPA part into a separate application which in turn is referenced from (in my case) the JSP.
When my module needs some additional configuration, it gets it using a REST API. This way the SPA part of the application is completely decoupled from the server-side rendered part.

Related

Is it possible to intercept html, css and js files used in angularjs?

I have already created an http interceptor and based on my observation, it only applies to all that uses $http service. What if I want to intercept even the css, html and js files used in the template? Is it possible?
This is the code of the interceptor I mentioned above:
app.factory('redirectInterceptor', function($q,$location,$window){
return {
'response':function(response){
if (typeof response.data === 'string' && response.data.indexOf("My Login Page")>-1) {
$window.location.href = "/login.html";
return $q.reject(response);
}else{
return response;
}
}
}
});
app.config(['$httpProvider',function($httpProvider) {
$httpProvider.interceptors.push('redirectInterceptor');
}]);
I want to be able to do an interceptor for css, html and js (for template) just like the one above.
As you said,
it only applies to all that uses $http service
So, if you want to intercept the requests for html,css and js files. It is best done on the server, rather than the client.
you can intercept html files
var requestInterceptor = function (config) {
if (config.url.indexOf(".html") != -1) {
//custom logic
}
}
though above does not work with .js or .css because they are loading using tag.
.html files are saved in template-cache and fires $http requests...
though you should go ahead and test what all being requested by doing console.log(config.url) in the interceptor to be sure..
This is a classic X-Y problem. You're thinking of a solution to your problem but it's the wrong way to go about it.
This line, from your comment, explains the actual problem:
but the js files that I'm referring to are the business logic of the project. So making it public is not an option.
So, your problem is you don't want to expose business logic to people who haven't/can't login.
There are several solutions to this. But it all boils down to one thing: separate your business logic from common js code used for UI etc.
Once you've separated your js into two parts (not necessarily two files but it must be at least two files, it can be more) you can expose your common js file(s) as public. Then you can decide how to handle loading your business logic:
Letting it Fail
This is probably the simplest strategy. Just do nothing and it will fail to load. Presumably you only need your business logic on logged-in pages so not having it in the landing or login pages should not be an issue.
Dynamicly Include it in the Template
Just omit the script tag that loads the business logic js if user is not logged in.
Load Business Logic Dynamically in JS
Either load it using AJAX then eval it or use require.js or use jQuery getScript() or something similar to load the business logic only when the user is logged in.
If you're creative you can probably come up with a couple more ways to handle loading the business logic JS. Whatever it is, the key is you need to make the common js and css files public.

What are the best practices for separating concerns with Angular and Express?

I feel like both Express' and any MEAN stack tutorials gloss over this, so I decided to ask here.
See also these similar SO posts:
Why would one want to use Express instead of AngularJS?
Angular and Express routing
Using plain HTML with Angular directives/attributes as the view engine in Express, what's the best practice for rendering page partials in a single layout template with regards to routes?
How do you do this with HTML/Angular as your view engine?
In Jade, you'd do something like block content.
Do you use the Angular Router, ng-view and use directives?
If so, what's the point of Express? Just a server? Why not just use Connect?
P.S. If you're wondering about Jade or EJS, I'm just learning Express, and Angular, so I'm trying to keep language abstractions to a minimum.
I guess my confusion originates from the overlaps between Express and Angular in regards to templating and routing, but Express focuses on the server-side, and Angular, the client. For someone just learning these, it's tough to know how to implement when everything is so wide open.
I'm looking for detailed, specific implementation code examples that use best practices when it comes to separation of concerns. Seeing it and having it explained in context is how I learn best from others.
Check out angular-blocks if you want jade-like blocks:
https://github.com/wmluke/angular-blocks
It's important to understand that Angular and YOUR_SERVER is generally irrelevant. It's a matter of "where do my files go". As single-page application suggests, it is a single static route. I'm sure Connect would handle this just fine, but the server portion of your application likely has more concerns than simply serving a static page. Authentication, business logic, API routes and other concerns come into the picture at some point, so Express (and its ecosystem) makes a lot of sense.
Your single-page application will definitely have its own routes. These are unrelated to your servers routes, which will include the static route to the Angular application page, and also any routing for API calls that the Angular app will be making.
It's important to understand that you are writing two distinct and separate applications, connect via an API. The fact that your Node server is delivering the static HTML and JS is, for the most part, coincidental. The Angular application should be considered, and developed, in an isolated, decoupled way for best results.
Express and angular serve totally different purposes.
In most MEAN-like stacs situation (for example just express-angular), express acts as server PLUS API provider.
You use app.get('/') with any server side templating like jade (just to have cleaner html files...), then You use app.get('/partial/:name') to handle all partials with same template language.
then, You use app.get('/api/anyapi1'), app.get('/api/anyapi2') to provide whole api to angular - no matter what it will be - some mongo or postgres handling, or just Your static json files.
In new express4 You can also create dedicated api route with:
var api = express.Router();
api.get('/somget', function(req, res) {
res.send('some json');
});
// init api route. all api routes will begin with /api
//(like above api.get will be at /api/somget)
app.use('/api', api);
You can also deal with sessions and authorization on express side, and whole awful lot of stuff, that shouldnt or cant be done on client side.
Hope it helped.
EDIT: speaking shortly: express is backend with http server, other services and api, and angular is whole frontend which consumes what backends provides.
Having such separation You can even provide that backend api to others, or build different services on top of it.
Correct, the MEAN stack puts an emphasis on making most of your logic on the front end. Your express server will act as a mule to save, read, validate, and delete data based on the get and post request you make from the front end.
The idea is to have all your front end code in a public folder of your express app.
`app.use(express.static(__dirname + '/public'));`
Then simply make a route that renders the index file as such
`app.get('/',function(req,res){
res.render('index')
})`
With this in mind you may we wondering if there is a solution that can generate an api for you so that you just name your models and the rest is done via angularjs services. There is.. http://loopback.io/ just name your models, relationships and restrictions. It will generate an enteprise level api for you to play with.
For a complete working example on how routing is done and how to model your app check out this tutorial: http://www.ibm.com/developerworks/library/wa-nodejs-polling-app/

The best way to pre-populate remote data in AngularJS app

In my AngularJS app, I need to retrieve multiple collections of static data from remote REST endpoints. Those data collections will be used throughout the entire application life cycle as static lookup lists. I would like for all those lists to be populated upon the initial application startup, and to be retained and made available to multiple controllers. I would prefer not to load any additional data dynamically, as one of the assumptions for this particular app, is that, once loaded, any further network connections may not be available for a while.
It is OK to take an initial hit, as the users will be preoccupied by reading a static content of the first page anyway.
I was thinking of making this mass loading a part of the initial application run block, and stick all this static data into various collections attached to the $rootScope (which would make that available everywhere else)
What is the best way to handle this requirement?
Interestingly enough, I just wrote a blog post about extending the script directive to handle this very scenario.
The concept is simple. You embed JSON data in your page when it loads from the server like so:
<script type="text/context-info">
{
"name":"foo-view",
"id":34,
"tags":[
"angular",
"javascript",
"directives"
]
}
</script>
Then you extend the script directive so it parses the data out for you and makes it available to other parts of your application via a service.
if(attr.type === 'text/context-info'){
var contextInfo = JSON.parse(element[0].text);
//Custom service that can be injected into
// the decorator
contextInfoService.addContextInfo(contextInfo);
}
You can see a live demo of it here: http://embed.plnkr.co/mSFgaO/preview
The way I approach this is to use a service (or a collection of services I nest), and set caching to true in the $http get functions. This way the service can be passed into any controller you desire, having cached results available to you without the need for additional http requests.
I can try to put this into an example if this is unclear to you, let me know.
edit: you can either wait for the first call to this service to do this caching, or do this on app load, either way is possible.

Different base url for page routing and templates/partials/RESTful API

My Angular app is splitted into several subapps. I'm working with laravel which is also responsible for the routing between the subapps.
So there are the following urls handled by laravel:
ModuleX: /moduleX
ModuleY: /moduleY
ModuleZ, Item n: /moduleZ/item-n (unlimited amount of items)
And finally on top of these there are my 3 Angular subapps.
So for example: /moduleZ/item-1/#/hello/world
Additionally the templates, partials and a RESTful API are served by laravel under the following urls:
/templates
/partials
/api
If I set the base url with the html tag <base href="http://www.example.com/app/"> I can use relative urls for templates, partials and the api but not for the routing. I'll allways have to add the module url part like that moduleX/#/hello/world.
If I set the base url like for example <base href="http://www.example.com/app/moduleX/"> I can write all links like #/hello/world but the templates, partials and api requests aren't working anymore.
The whole app also sits in a subfolder so I can't just use for example /templates.
So basically my problem or the question now is, what's the best way for handling the different base urls? I don't really like it to prepend the module name to every link.
Look it's might be a particular solution, but may be you should use filters for urls?
For example:
.filter('routeFilter', [function () {
return function (route) {
if (some condition mean this direct html link){
return 'MODULE-X/' + route;
}else{
return route
}
};
}])
I would suggest you let (sub-)apps know their real base not the parent's one, but you make the server responsible for climbing the path hierarchy to find higher level shared resources for missing local ones. This also makes it very easy to prototype new sub-apps, test changes to common pieces independently first, etc.
In a webserver like Apache, this would look like a rewrite rule (conditional on not finding a file) it just substitutes the same file in the parent hierarchy.
In laravel (according to the router docs) it looks like you can add optional 'directories' to your current rules, i.e.:
Route::get('/.../app/templates/{name}', function($name)
...
becomes:
Route::get('/.../app/{module?}/{item?}/templates/{name}', function($name, $module, $item)
...
You could then use $module and $item if you need to test a resource change with specific sub-app/items.
The drawback in making the server responsible for handling inheritance is the independent client fetch/cache of identical resources with different paths. But you can at least choose between large file inefficiency or access latency by using either rewrites or redirects. You can also always hardcode significant paths in production clients later and still benefit from having a hierarchy for testing and graceful handling of occasional errors in client side links.
You can do it in a simpler way if you use combination of service and directive.
You can implement a directive similar to ngHref which when given a link will transform it and append the given link back. It will be injected with a service which will give it the base url or relative url or anything module specific.
This service which is injected in directive will be configured using serviceProvider in app.config block of each sub-app. Since angular injector have only one instance of each service I think you will need more than one injector or one injector per sub-app. Its unclear whether they share injector among them in your app.
You can configure each service according to module to return different base paths. Which will be appended by directive to each link every time.
With this you can use <base href="http://www.example.com/app/"> and that should solve your problem.
I haven't written any code but I can help if you need it.

What is the point of AngularJS routes?

Im creating a website and I chose to do it in AJ.
I have two folders:
Gateways => some php files which retrive data from a mysql db and echos the data as json.
Views => Partial html files which are basically the template for each page. eg Users, Items, etc.
then I have a index.js file which handels the request process and routing:
angular.module('Index',['addon'],function($routeProvider,$locationProvider){
$locationProvider.html5Mode(true).hashPrefix("!");
$routeProvider.otherwise({
templateUrl: '/views/index.html',
controller: "index"
}).when("/items/",{
templateUrl: '/views/items.html',
controller: "items"
})
}).
controller("index",function($scope,$http){
$scope.users = [];
$http.get("gateways/list.php").
success(function(d){
console.log(d);
if(angular.isArray(d)){
$scope.users = d;
}
});
}).
controller("items",function($scope,$http,$routeParams){
$scope.items = [];
$http.get("gateways/single.php").
success(function(d){
if(angular.isArray(d)){
$scope.items = d;
}
});
}).
What is the point of all this route providers in AJ except its elegancy?
Dont they just slow down the site because of number of the requests?
I could just write the php code from the gateways files directly in the templates files?
Am I doing it in the wrong way?
You might be missing the point of using frameworks like AngularJS. They are mostly for Single Page application and ajax intensive. And let me begin that the number of requests don't really slow down application. Remember how Gmail used to be at first without Ajax ? Was it faster than the current implementation ?
Now, when you build a single page application, the app sends req to server and server responds in JSON or XML. In frameworks like AngularJS or any other, server sends the JSON response and we render them using client side templates or DOM. This saves enormous resource from the server side since server doesn't have to parse the array and render the template. So if server had to render a table which has 100 rows, the bandwidth to send to your browser might be 20KB whereas only JSON might be 5KB and a string or DOM template with 1KB to do the rendering. So, you're actually having your visitor's browser do a lot of job. It's all about calculations/computations. Think of a statistics table where there are columns and some computed values to be presented in a data grid. With Client side frameworks, your server would just respond as JSON and browser (with JavaScript) will parse,calculate and render it in template.
As for the question of using a routerProvider, it's essential to bookmark and use browser navigation button. Just like a traditional url has a view, a URL in client side app has a view which should be bookmarkable and should support navigation.
AngularJS, as a JS framework, works it's magic in the client - meaning it's your computer that processes the template files, applying any logic needed. PHP can't do that - it's a strictly server-side language. When you request a PHP "file" via AJAX calls, you don't really get the php file, but the processed output that your servers produces (in this case, a list of users that it will map to an object). If you simply include the PHP logic in your templates, in the best of cases the HTML that angularJS reads will have the list you need to show, but there won't be an actual list model (that angular can filter/change/reorder/save/delete at will) in the angular scope.
But you are right, at the level you are working on it can seem to only complicate and slow down processes (with the minor advantage of simplifying your work). But when things get denser, that modularization (and separating the controller (i.e. Users controller) from the different views it can be applied to (view, list, edit, details, etc) is what keeps your application structured.
I don't think they slow down the site in any way. If your concern is retrieving both the html and the json for each page, that is not how it works.
The html templates are retrieved, compiled and cached only once by angular-js. You can see this using some debug tool, like firebug.
So when the user switches to a different page you only make a json request to the server, which -generally- is a faster and lightweight operation than rendering html server side and retrieving the full html. (anyway, nothing stops you from doing that if it is better for you)

Resources