Custom directives on AngularJS pages without specific ng-app module set - javascript

I have some simple pages that don't need a specific application module to be provided in the ng-app attribute. But those pages also use some of my custom directives.
As it seems natural I've put all my directives in separate namespace (namely module) i.e. MyApp.Directives.
This is all great when I also provide my application module, because I add MyApp.Directives as dependency and it works.
angular.module("MyApp", ["MyApp.Directives", ...])
But. As said I also have some very simple pages, that don't really require any particular application module because they don't need any custom controllers or anything. They're just driven by ng-... attributes/directives.
Question
I know I can simply add all my custom directives to ng module and they will become accessible to all pages. Those with custom application module and those without. But this beats the purpose of modules, so I'm wondering if there's any other way to tell dependency injector of my additional directives/filters?
I would like to avoid any unneeded code in my application to keep is small and maintainable. (what AngularJS is all about). What I'm looking is actually some sort of hack that I'd be using in my directives' files to make ng module aware of my directives but without adding them to ng module directly... A rather advanced Angular question as it likely involves some internals manipulation.
I've tried manully adding my directives' module to angular.module("ng").requires array but that didn't do the trick.

#1) If you only have one module you can do it with ngApp:
<html ng-app="MyApp.Directives">
#2) If you have multiple modules you can use angular.bootstrap like so:
angular.element(document).ready(function(){
angular.bootstrap(document,['MyApp.Directives','MyApp.Filters']);
});
#3) Or just create a simple module for declaring dependencies:
<html ng-app="myApp">
......
<script>
angular.module('myApp',['MyApp.Directives','MyApp.Filters']);
</script>
If we could only write something like this:
<html ng-app="MyApp.Directives MyApp.Filters">
I made a patch to the source code:
function angularInit(element, bootstrap) {
// some code
if (appElement) {
bootstrap(appElement, module ? module.split(/\s+/) : []); // split by spaces :)
}
}
Here is a demo: http://plnkr.co/edit/kSrY3WYzLG39NJ4UgTRM?p=preview

Related

Proper way to include a js library file in a directive, avoiding relative path that may change

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.

ng-app or angular.bootstrap

I was thinking when it would be best to not use the ng-App directive and instead go for angular.bootstrap. I understand from documentation what ng-App directive does and how it helps in telling compiler to set root of compilation. So my question is as to why I should use angular.bootstrap? What do they mean by saying in documentation that "If you need to have more control over the initialization process, you can use a manual bootstrapping method instead" documentation. Then I would also like to know as to for the solution that I am thinking for my application. I have one index.html file with one ng-app directive. Now for my application, I have different APIs, lets say for admin, students and instructors. So this is what I was thinking.Have the following files:
index.html
admin.js
students.js
instructors.js
I will have controllers for all of them and separate moduels, which will get the data from those APIs. Each div that will display the data from those controllers will be associated with the specific module, using angular.bootstrap and index.html will not have the ng-App directive. Is this the right approach ? Should I be just using ng-App and multiple controllers and a single module? Any help in understanding this is appreciated. Thank You.
One guideline that might help you is that you can only use ng-app once, but you can use angular.bootstrap multiple times
"If you need to have more control over the initialization process, you can use a manual bootstrapping method instead"
This means that with ng-app whenever directive is encountered bootstrapping will start automatically.
But with manual bootstrapping we can control it, say we want some data to be loaded first, to check for something defined or not or even as normally we do with checking of DOM ready event.

Using Angular Dragula without RequireJS

I would love to implement Drag and Drop in my Angular project using the angular-dragula module (https://github.com/bevacqua/angular-dragula). However, it seems to be heavily dependent on RequireJS. I've not used Require for a while and only then for an example app or two. Is there an easy way to untangle Require from this module?
The author seems to think it is simple (https://github.com/bevacqua/angular-dragula/issues/23) and has shut down similar questions as well without a real explanation. I've looked at the code and don't see how to load the module without adding RequireJS to my project (which I don't want to do). Am I stuck with either not using this module or adding Require or is there a way to use this without Require?
OK, after help from those who commented (thanks everyone!), I was able to get this to work. There are a couple things that you need to do. First, I was bundling this module with the rest of my modules and trying to call it. That will not work because it needs to initialize with a parameter (angular). Therefore, you need to do the following:
Add a reference to angular-dragula.js (or the min version) to your index.html page below the declaration for angular but above where you create your app.
When you declare the dependencies for your app, specify angularDragula(angular) (not in quotes).
Use dragula as you normally would. If you need to access the service, the name would be angularDragula.
For example, here is my declaration of app:
var app = angular.module('app', [
'ngRoute',
angularDragula(angular)
]);
And then to get a simple list to be drag and drop capable, this is my html:
<div dragula='"bag-one"' dragula-model="vm.items">
<div ng-repeat="item in vm.items">{{ item }}</div>
</div>
Note that I do not declare angularDragula anywhere, unlike the examples. In the example the author gives, he requires angular and creates the angular variable and then he requires angular-dragula and creates the angularDragula variable. This is not needed if you are not using RequireJS as long as you load the scripts in the right order.

Why ng-app not ng-module?

I understand that ng-app initializes a module in AngularJS as follows:
var app = angular.module('myApp', []);
<html ng-app="myApp">
But when I teach this to someone new to AngularJS or watch a video, instructors inevitable fumble over the inconsistency in the terminology between app and module. AngularJS is so well thought out as a framework that I'm surprised it hasn't changed to:
var app = angular.app('myApp', []);
<html ng-app="myApp">
OR
var app = angular.module('myModule', []);
<html ng-module="myModule">
Has anyone been following the project long enough to know the history on this part of the framework?
I don't think Craig is asking what does ng-app do or how does it work.
I think he's asking why did the people that created angular name that directive ng-app. Why didn't they name it ng-module. ng-module would be easier to understand.
For example ng-controller should name a controller, ng-module should name a module. The angular methods to create them are named module() and controller(), there is no method or entity called "app".
I tend to agree with Craig. That said if I were go speculate why they named it ng-app I would think it's because you are only allowed to have one ng-app directive in your HTML. If you wanted to have more than one module associated with your HTML page you can do it programmatically.
So ng-app is more of a utility to bootstrap your HTML with a module, it is not a generic way to associate modules with your HTML.
If you look at the documentation that's what it suggests:
Use this directive to auto-bootstrap an AngularJS application. The
ngApp directive designates the root element of the application and is
typically placed near the root element of the page - e.g. on the
or tags.
Only one AngularJS application can be auto-bootstrapped per HTML
document. The first ngApp found in the document will be used to define
the root element to auto-bootstrap as an application. To run multiple
applications in an HTML document you must manually bootstrap them
using angular.bootstrap instead. AngularJS applications cannot be
nested within each other.
http://docs.angularjs.org/api/ng/directive/ngApp
All that said if you want an ng-module directive you could always write your own to wrap the angular.bootstrap() function. You can find more details and code about how to do this on a blog post I wrote about it: AngularJS: Getting around ngApp limitations with ngModule
ng-app means: That page has Angular in it!
ng-app="module" means: That page has Angular in it and necessary controls/services/etc are defined in that module.
ng-app defines the main or bootstrap module of your application, which should perform the initialization task of your application. There may be case where at run time you want to decide what which should be the main module of your application. Like in java you have many methods and classes but you define one main method as starting point. Similarly, in angular you have many module, however, you define one module as the starting point of application.

How to define a global directive that can work like ng-model?

The most related question I can find on SO is "How to share a single Directive across multiple modules in AngularJS". But I need something a little different. I need something that can work more or less like ng-model. The page does not need to have a named ng-app.
Here is the real problem I want to solve:
I would like to define some template as samples that shows good accessibility. For example, the label for a required form field, should have arterisk (*). However, I don't want to force the users to define a named module in the JS file. Instead, they can just add ng-app(without name) to the html or body tag and include my JS file.
Your directive(s) is/are defined in an Angular module. I believe you have two choices to load such a module:
put ng-app="myModule" on an HTML element
manual bootstrap, hence no ng-app
You can add your directive directly to the ng module:
angular.module("ng")
.directive("myDirective", function() {
...
})
But beware of potential name conflicts with new directives introduced by the angular team.

Categories

Resources