Managing custom directives - angularjs

I need to make some custom directives. Every tutorial shows building the directive relative to the controller where it is to be used. I'm sure this is not the right way if you need to put it into another controller.
I have a global controller. Should I put my directives there? I also have a Utilities factory and inject this into my controllers(this keeps everything tidy and manageable). Do directives work the same way?
How do you manage multiple directives and where do you put them?

Add your directives in separate file like directives.js and use those directives in many views or controllers.
directive.js should be included after your app.js
For example if your app.js is like:
var app = angular.module('myangularapp', ['ngResource']);
then your directive.js should be like:
app.directive('confirm', function(ConfirmService) {
});
app.directive('alert', function(AlertService) {
});

Related

Angular 1 common service/module/library for multiple "apps"

I can't describe it very well but:
I have one angular app for "one" functionality.
E.q. I have "campaigns" functionality. Add, Edit, Display all, display in another way.
For add and edit I have that same app and controller and context etc.
For rest I have different folders with app, controller, context, config, eventHanlder etc.
But all of them have simillar code in ~70%.
It is context with download and upload data via $http to ASP.NET WebAPI project.
And few methods in controller.
I want "merge" it into one but I cant don't want merge these functions into one app because they have different "view".
So I was thinking about:
Make "routing" app for these simillar apps.
one context, config, and controller same in more than half
some different options so it won't be "SoC"?
Move common from "context, config, controller" to another files/apps and inject them to concrete controller.
But I don't know how to do it.
I know I can "factory" method to app inside it config but I want these "services" be indepentent to controllers and apps. As different app in different catalog. So I can inject them via controller.
How it is possible?
Yeah I really new in Angular ;)
Question 1:
I would advise to look at the ui-router module. This module allows you to define url routes to states with views and nested states/views. Very useful for anything more than a single page app.
Question 2:
Sounds like you're talking about setting up a few angular.modules that depend on one another.
In general you would group related services, controllers, configs into a module. If another module needs to use one of those, you make that module depend on the other.
Example:
// myApp.foo module
angular.module('myApp.foo', [])
.factory('Foo', function(){
return {
data: {
foo: 'angularjs is cool!';
},
doStuff: function(){
}
};
})
.controller('FooController', function($scope, Foo){
$scope.foo = Foo.data.foo;
Foo.doStuff();
});
// myApp.bar module
angular.module('myApp.bar', ['myApp.foo']) // notice dependency on myApp.foo
.factory('Bar', function(Foo){ // you can inject Foo because of dependency
return {
data: {
bar: 'using angular modules helps us organize'
},
doStuff: {
},
doOtherStuff: {
Foo.doStuff();
}
};
})
.controller('BarController', function($scope, Bar, Foo){ // you can inject Foo into controllers too
$scope.foo = Foo.data.foo;
$scope.bar = Bar.data.bar;
$scope.doFoo = Foo.doStuff;
$scope.doBar = Bar.doStuff;
$scope.doOtherBar = Bar.doOtherStuff;
});
It is always good practice to think about and develop your modules in a way that they can be reused in different projects.
Update: (RE: question about /AppCommon, /App1, /App2, /App3)
Just make your service in: /AppCommon/my-service.srv.js*
It would look something like:
angular.module('MyCompany.Common', [])
.factory('CommonService', function($http){
return {
doStuff: function(){
$http.get('/some-url').then(function(res){
});
}
};
});
And in your /App1, /App2, /App3 projects:
Include that js file into your HTML:
<script src="/AppCommon/my-service.srv.js></script>
Inject the MyCompany.Common module into the areas of the apps where you need it.
angular.module('App1', ['MyCompany.Common']);
Inject the CommonService into the app's controllers/services where you need it.
angular.module('App1', ['MyCompany.Common'])
.controller('App1Controller', function($scope, CommonService){
});
*Note: You can name your javascript file however you want. I have found it very helpful to include .srv in files containing services, .ctrl in files containing controllers, .drv in files containing directives, .tpl in template files, etc... This goes along with the best practice of having one thing per file.

Creating custom filters in Angular

I am learning Angular and need to create some custom filters.
Do I create one filters.js file and put all my filters in there similar to all my reusable factory.js?
Eg: I have a utilsFactory.js and I put reusable functions in here.
Does this then get injected into the controllers? Or is this loaded in the $rootscope somewhere?
I have seen many examples on how to create them but not how to store and manage them and how to access them properly
filter.js
angular.module('achApp', [])
.filter('myUpperCase', function(){
return function(value){
return String(value).toUpperCase();
}
});
Controller
(function(){
var DevbController = function($scope, utilsFactory, $filter){
$scope.greeting = 'hello';
};
DevbController.$inject = ['$scope', 'utilsFactory', '$filter'];
angular.module('achApp')
.controller('DevbController', DevbController)
}());
Filters are generally created for use in your templates (HTML). For example:
<p>{{somethingOnScope | myFilter}}</p>
You can use them in your JS files by injecting $filter, and then getting a reference to your filter like: $filter('myFilter');
You can see usage examples in the filter documentation:
https://docs.angularjs.org/api/ng/filter/filter
Where and how exactly you register your filters is a matter of style. I personally try to follow john papa's advice and create only one injectable item per file.
On another subjective note, I prefer to minimize the use of filters, especially custom ones. If you want to use them primarily in your JS, a service/factory feels cleaner to me, and if you're tempted to create one for use in your templates, often you can instead just change the thing before putting it on the scope.

How to create a directive to be used in any module?

How can I create a directive without linking it to a specific module which can be used in any module, such as the build-in directives.
A directive or service has to belong to a module. What you can do is create separate modules for your directives and then inject them into your main application module. Here's my set up:
window.app = angular.module('app', ['ngRoute', 'app.system', 'app.animations', 'app.cart']);
angular.module('app.system', []);
angular.module('app.animations', []);
angular.module('app.cart', []);
Now your Service can be in its own module and called from within the app module. This is essentially what Ajay said.
angular.module('app.cart').factory("Cart", ['$resource', function($resource) {}]);
Short answer: no, it is not possible. All directives must be part of a module.
The Angular docs say
Much like controllers, directives are registered on modules. To register a directive, you use the module.directive API. module.directive
There isn't a way to define a directive outside of a module.
The Angular built-in directives themseves are defined on a module called ng - see the source code.
This module is created using the Angular internal method setUpModuleLoader (see AngularPublic.js and loader.js).
This function is not part of the Angular public API, so you can't access it yourself. You need to define your directives in your own module. Any app module which depends on this module will be able to use your directives.
It's a very Angular way of looking at things - avoid public objects, but make things injectable wherever possible.
I think I understand what the OP means. Similar to libraries like Angular UI for Bootstrap. The OP would like to create directives, etc. that can be used in other apps without having to know the main app name.
You can do this like so:
angular.module("hello.world", [])
.directive('hello', function() {
return {
template: '<p>Hello, world!</p>',
restrict: 'E',
link: function (scope, element, attrs) {}
};
});
Saved as 'hello-world.js' for example.
Make sure you include that JS in your page. Then inside your main Angular app:
var app = angular.module("myApp", ['hello.world']);
Then anywhere in your HTML under the app scope, you can insert:
<hello></hello>
And that directive will take over rendering a paragraph tag with the words "Hello, world!" within.
My understanding is that you can do this with all Angular objects - services, factories, providers, etc.
If I m not mistaken even the built-in directives belong to a module (ng module). It just that you don't have to explicitly declare a dependency on it as it is done by the framework for you. That's why you will always have to declare a module, add directive(s) to this module and depend of this module in other modules. Something like that :
// Reusable module with directive(s)
angular.module('directives', [])
.directive('rating', function () {
...
}
// other module that rely on teh first one
angular.module('MyApp', [
'directives',
...
]);
//Module 2
angular.module('MyModuleWithDependency', [
'directives'
]);

Are there guidelines for when a directive should have its own controller

I have written a couple of directives now. One or two of them used their own controller. I have been looking at how some of angular's own directives work as well as some of the angular UI bootstrap directives work.
They also some times use controllers. For the most part it seems like controllers just add a nice way of wrapping code and keeping it more modular. I am sure there must be some more sound advice on when exactly your directive should gets its own controller.
From the docs:
... readers may be wondering what the difference is between link and controller. The basic difference is that controller can expose an API, and link functions can interact with controllers using require.
If you have two or more directives that need to share data between them, it's recommendable to define a controller in one directive and then require it in another:
.directive('myFirstDirective', function(){
return {
//...
controller: function(){
this.doSomething = function(){...};
return;
}
//...
};
})
.directive('mySecondDirective', function(){
return {
require: 'myFirstDirective',
//link's fourth param is the required controller object.
link: function($scope, $iElement, $iAtrrs, requiredController){
$iElement.on('click', function(){
requiredController.doSomething();
return;
});
return;
}
};
});
If directives are independent from each other, then it's fine to only have link functions.

'Stand Alone' Controllers VS modular controllers in angularJS

I am new to angularJS. I have been reading many code examples and I often see controllers defined as:
function MyController($scope) {
//code here
};
I however am using the method below to define my controller, as I wasn't aware there was any other way to do it.
angular.module("csApp.controllers", [])
.controller("main", function ($scope) {
//code here
};
How does the first method work? Is there some sort of naming convention I am missing here?
Are people using the first method simply adding these functions as global variables by placing them in in script files after angular loads?
How would you connect a global variable to a route if the controller is not registered with angularJS?
Thanks!
The AngularJS Dependency Injection framework can always find controller constructor function in global scope as they are global by nature. Even the ng-controller directive has this in its documentation
Name of a globally accessible constructor function or an expression
that on the current scope evaluates to a constructor function.
When using $routeProvider you can provide the route definition a Controller class or a quoted controller name which has been registered using the module api. These two are valid
route :{controller:MainCtrl,...}
route :{controller:'main',...}
The module based approach is preferable because it stops one from polluting the JS global namespace.
You just need to initialize your module, then you can declare your controllers with the two methods.
The first method make it easier and more readable when you have for instance 5 controllers, or if you want to split them in differents files. But they do the same job. All you need to do is keeping track your controller name.
function MainCtrl($scope) {
// do your stuff
}
<!-- Using the function name here -->
<ANY ng-controller="MainCtrl">
<!-- your HTML data -->
</ANY>
More info in the API Doc.

Resources