In C programs, it is easy to add a header file containing a set of library functions.
#include "ownlib.h";
In node.js, it is just as easy.
require('./ownlib.js');
I am trying to do the same for a AngularJS controller but there seems no easy to do it. What I do now is to add functions like those below at the bottom of my Angularjs controller controllers.js. Unfortunately, this make the controller file grow huge over time.
function convertXXXToJson(obj) {
...
return output;
}
function convertYYYToJson(obj) {
...
return output;
}
How to conveniently add an external library file to an angularjs controller?
It will be a nightmare if I have to create a module and do dependency injectancy for each external library file.
You can just add the new functions in a separate file or multiple files and include them through script tag in your html file and you are done.
<script href="controllers-part1.js"></script>
<script href="controllers-part2.js"></script>
Now coming to the order in which you need to include the script tags in your html file. The order matters if you are executing something in your controllers.js immediately, and it uses some functions defined in controllers-part<x>.js. Then in that you need to include controller-part<x>.js files before controllers.js. Otherwise you can include them in any order.
Related
I am working on angularjs project that I generated using yeoman angular generator.
I have a jQuery function that I need to use in most of my html views.
A possible solution is to add this function to a script.js file for example, and add this file as reference in the html views that require this function. However, I don't think this solution is good.
When yeoman generates an angularjs project, in its index.html file, it adds a section
<!-- build:js({.tmp,app}) scripts/scripts.js -->
within this section, the different script files are added since as I think, on build, those files will be unified in a single scripts/scripts.js file.
I tried to do the same by adding the function to a script file, and added the reference of the this script file to this section. The problem is that the function is not working when I try to call it from any view.
What can I do to solve it?
DOM manipulation is done with directives in angularjs you will need to check out the docs: https://docs.angularjs.org/guide/directive
If you are not manipulating the DOM you can create a service that can be injected into any controller.
Services documentation: https://docs.angularjs.org/guide/services
from there you can assign a function in the controller to the scope that can be accessed in the view. e.g.
$scope.MyFunction = function(){
// Code goes here
}
you can call the function in the html as
<div ng-click="MyFunction()"></div>
I have a project which is not using any method for including angular code other then loading them directly into our html page (and won't get permission to include any tool for awhile from my manager).
Currently if I want to use a provided javascript/angular/bootstrap element I would simply include it in my index.html, something like:
<script type="text/javascript" src="../lib/angular/angular-file.js"/>
I am now writing a directive. In the html template I want to use an already written third party angular directive to provide a tree view. I thus would want to include this script within my directives html template to insure it's loaded, rather then trusting this to the index.html has already loaded the script.
However, I don't want to use a relative path, or at least am afraid doing so will cause my directive to break later. the html template for my directive is buried under a tree structure, something like " portal/modules/simulation/templates/whatever" I don't want to have to place "../../../../../lib" in the template because it's ugly, but also because there is a chance that we may move the angular files around and I don't wan that to break my directive.
Is there a cleaner way of including the library without making a presumption about multuple layers of file structure, some way to work relative to the 'top layer' of my file structure etc?
is it considered clean for my directive to have it's own lib directory that contains the third party angular directive, rather then being part of shared lib directory? For that mater I believe that the third party tree view directive I'm using is dependent on other angular and jquery code, so I don't know if I may accidentally be dependent on something in the top level index.html file loading some angular/jquery code my directive uses without realizing it. Am I over worrying about making my directive stand alone when I shouldn't?
Generally I pack up templates using grunt and grunt-angular-templates. If you use something like this, you can reference your template as myModule/fileNameOfTemplate, and since the template is already in memory (using the $templateCache) you don't make any extra requests and the code doesn't care at all about the path to the actual file.
Without adding extra modules, build steps, etc...
foo.js
var fooModule = angular.module('foo', []);
fooModule.run(['$templateCache', function ($templateCache) {
$templateCache.put("foo/mytemplate.hmtl", "Really" +
"really" +
"long" +
"string");
}])
fooModule.directive('bar', function () {
return {
templateUrl: 'foo/mytemplate.html'
}
});
Now it doesn't matter where you store the module - you're just pulling the file out of the template cache.
Alternatively, templateUrl can accept a function - you could write a function to determine the path of the module or something.. but that's going to be super brittle.
I my webapp I use about 30 js files, each file containing 1 function. All these function are now selfinvoking and have references to each other.
The problem with this is that the order of scripts in the index.jsp matters. If a method is called on a function which has not been invoked yet we get a undefined error.
For a while we could overcome this by controlling the order of the <script> tags, but I would like to do this by using a loader script.
I have set up a small fiddle to show my concept. My biggest concern is that I have to declare my objects globally, in order to have them be accessible in the jquery(document).ready() function.
Is this an OK pattern? Any hints highly appreciated!
You could use RequireJS or similar loader, which would handle script dependencies for you.
You would need to modify each of JS file to make it a module in a similar fashion to this example:
// File: module3.js
define(["module1", "module2"], function(m1, m2) {
// Here, module1 and module2 are guaranteed to be loaded.
});
Then, you would make one "main" script (I usually call it main.js) and require several modules:
require(["module3"], function (m3) {
// Here module3 is loaded, as well as module1 and module2
// - because module3 depends on them.
});
And put this in your HTML:
<script data-main="scripts/main" src="scripts/require.js"></script>
Try to build your server-side architecture to serve proper js files (and other static files) per page. Create 1 minified js file for page and initialize objects scope in html files.
I have a html file with multiple script tags(close to 20). I've decided to concatenate all the JS files into one and then minify the concatenated file. I am using ant tasks to concatenate and will do so for minification as well. I am aware that I need to provide the option of a non-concatenated/non-minified version for the purposes of debugging(aka in the dev env).
I was wondering how to achieve this. For ex: the file main.html has 20 script tags, one way I figured to do it was use a HTML preprocessor and conditionally include script tags:
#ifdef perf
<script src="main.min.js"></script>
#else
<script src="ctrl.js"></script>
<script src="services.js"></script>
<script src="directives.js"></script>
<script src="model.js"></script>
.
.
.P.S
<script src="file_no_20.js"></script>
#endif
main.min.js is the concatenated and minified file during the build process using ant.
Is there a better way of doing this? What are the downsides of this approach?
Thanks,
Chris.
P.S: Thinking of using the http://fmpp.sourceforge.net/ for html preprocessing, any other suggestions are appreciated.
Chrome supports an awesome feature called "source mapping" that is perfect for this. I'd suggest you read the guide here for more info:
http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/
There are some caveats if you're using AngularJS in regards to minification. From the docs:
Since angular infers the controller's dependencies from the names of arguments to the controller's constructor function, if you were to minify the JavaScript code for PhoneListCtrl controller, all of its function arguments would be minified as well, and the dependency injector would not being able to identify services correctly.
To overcome issues caused by minification, just assign an array with service identifier strings into the $inject property of the controller function, just like the last line in the snippet (commented out) suggests:
PhoneListCtrl.$inject = ['$scope', '$http'];
There is also one more way to specify this dependency list and avoid minification issues — using the bracket notation which wraps the function to be injected into an array of strings (representing the dependency names) followed by the function to be injected:
var PhoneListCtrl = ['$scope', '$http', function($scope, $http) { /* constructor body */ }];
Both of these methods work with any function that can be injected by Angular, so it's up to your project's style guide to decide which one you use.
http://docs.angularjs.org/tutorial/step_05
I suggest using tag libraries, something like http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/JSPTags4.html#67771 to acheieve this. Include your script's like:
<script:include src="myscript1.js" />
<script:include src="myscript2.js" />
<script:include src="myscript3.js" />
..
And the use a page parameter for your system to decide if the scripts has to be concatenated and minified. Something like below:
www.yourapp.com/app?debugMode=true
By default the scripts are concatinated and minified. If you are a developer working on the project just add a page parameter like debugMode=true. When debugMode is true, just render the scripts as it is.
There are many services out there in the market like http://developer.yahoo.com/yui/compressor/ that can be integrated with your project to do this job for you.
Do not compress the scripts everytime you load the page. Do it the first time and cache it so that you dont have to do it everytime. At any point of time to rebuild the latest script file, just add another parameter like ?rebuild=true so that all the latest files and minfied and cached. You could do the same with CSS too.
I have been doing some performance analysis on a few websites I am working on and I am noticing that a big problem is the inline scripts. For the external scrips I wrote an http handler which combines, minifies, and gzips the javascript into one file. This is then stored for reuse later by hashing the filenames.
What I am wondering (not sure if this is a good idea but I am posting to get some feedback) is if I remove all script elements with script text inside them and combine them into a single file. I then use the same process I am using for the external scripts and combine them into a single script.
John
Inline script always gets inside the page so needs to be traversed by every post or get to and from the server. Since you're using MVC it's quite easy to only have non obtrusive script files in your project as you have quite some control over the rendered html.
You also want to check out SquishIt.
Grz, Kris.
It is possible to minify and bundle inline javascripts in with external files.
As I mentioned here Minify inline javascript during build for ASP.net?
With templated Razor helpers you could create an extension method like
the one below:
public static MvcHtmlString AddScriptSource(this HtmlHelper helper, Func<dynamic, HelperResult> source, string key)
{
string scriptSource = source(null).ToHtmlString();
// Cache scriptSource here
return MvcHtmlString.Empty;
}
Which you would use like this:
#Html.AddScriptSource(#<text>$(document).ready(function() { $('h1').text('The current controller is #ViewContext.RouteData.Values["controller"].ToString()'); });</text>, "test")