This may be a dumb question. I know AngularJS controllers use javascript code to keep the application logic outside of the view. But I was wondering if I could link an external javascript file to a controller so it didn't have to be so long.
If it is possible would you also share the syntax of how I would do this. Something like:
app.controller('demoCtrl', ['$scope', function ($scope) {
$scope.msgtxt='Hello World';
src=somejavascriptfile.js;
}]);
If your issue is that the controller logic is too long, you are correct that it is a code smell. You want to make the controller as thin as possible, just enough logic to handle the view events and updating the model (scope). If you want to refactor your controller code, the first step is to extract out the logic into service(s) (in angular lingo providers / factories / services). The services can then be injected into your controller, similar to how you have injected the $scope service.
Read this sitepoint article for details on how to do this.
The next step might be look for logic (mainly UI related) which can extracted into directives.
In case you need to use an external javascript library within your angular application, the optimal way is to add that script to the scripts section of your html file, and wrap the functionality in a service or a directive (if it is UI related). Make sure to check if there are angular modules available out there for the 3rd party library you want to pull in.
Not only you can split your controller code among different files, but you probably should do that. An angular controller is responsible for the business logic behind a view, and only for that. You are doing it wrong if, inside the controller, you are (list not exhaustive) :
accessing your backend from it
manipulating the DOM
writing utility code for showing alerts in your application (for example)
Your components should be concise and of a single responsibility.
Here follows an example of how you would export some part of your code in a service. You do not link a js file from a controller, but you load it in your page, and inject the service as an argument of your controller :
1) Load your service in index.html :
<script src="js/factories/loggerService.js"></script>
2) Implement your service in loggerService.js
app.factories('loggerService', function () {
//
// Implement here some logging methods
//
// IMPORTANT: do not bloat this service with methods not related
// with logging
//
});
3) Inject your service in your controller :
app.controller('demoCtrl', function ($scope, loggerService) {
loggerService.info(...)
});
By the way, this loggerService would be useful only if you need something different than the service provided by angular built-in service $log
In a different file, define a service containing the logic and just call it from the controller.
app.controller('demoCtrl', ['$scope', function (ServiceFromDifferentFile, $scope) {
$scope.msgtxt='Hello World';
ServiceFromDifferentFile.doStuff()
}]);
Related
I'm fairly new to AngularJS and I want to have the best practices from start. I want to know where should I put which controller I'll be using for a specific template. For now I've used this two:
In the html of the template
<div ng-controller="ImageManagerController"> </div>
In my routes.js
.state('home',{
url : '/',
templateUrl : '/src/images/views/home.html',
controller : 'ImageManagerController'
})
Is one of them better than the other?
Thanks for your time!
When you do both you will create 2 instances of the controller, you don't want that
The biggest advantage of setting it in the routing config is that any related resolve will be made available for injection in the controller that is referenced.
Also when you have a lot of routes it is easy to look up which controller you would need to modify for any specific route when they are all listed in a config
Using ng-controller directive in HTML :
This scopes the controller to a specific element on the page/template. That can make the code easier to read when you need multiple controllers on a single page and it allows the controller to be more specifically scoped.
New $scope object will created on ng-controller.
visible with page source or inspect element.
Controller in Route :
Allows you to specify a single controller for a template. Since this is part of the routing it makes it easy to find the controller that goes with the page. I use this to store and load overall page logic rather than element specific logic.
New $scope object is created per route on the ng-view.
Not visible with page source or inspect element.
If you will use this <div ng-view ng-controller="ImageManagerController"> then you'd need to change that controller as the route changed. So basically the router does that for you, and uses the controller you specified when you defined your routes.
I hope these differences will help you in deciding which to use.
I have recently started working on ANGULARJS in which I was encountered a case where I need some guidance to go through. Am implementing a message section in my application(ASP NET MVC - ANGULARJS).Currently I have implemented the message section for a specific module under a particular ng-app and under particular ng-controller. Now I need the same functionality to be used inside another module. It's like duplicating the same code again that ng-app under that ng-controller which was not a good approach. I just wanted like and plug and play kind of approach for my ANGULARJS code.
I have used 2 service,1 directive under that particular ng-app and some functions inside a particular controller. All I want is to make these one a common code and to be used inside under any ng-app and ng-controller.
Is this possible? If so how can I achieve.
Let me know if the query was unclear
You said you used 2 service, 1 directive, and controller etc for your messaging feature. If you want to re-use it across various applications, you need to bundle all of this as a module. for example:
angular.module('customMessaging', [])
.controller('messagingCtrl', function(messenger, messageManager) {
....
})
.directive('messagingDir', function() {
return {
controller: 'messagingCtrl'
...
}
})
.service('messenger', function() {
...
})
.service('messageManager', function() {
...
})
Now you can specify this as a dependency of any of your angular applications as shown below to access the directive, services and controller anywhere in the app:
angular.module('myfirstApp', ['customMessaging']);
angular.module('mySecondApp', ['customMessaging']);
Thanks for the suggestions. I have moved the message related functions such as services, directive and controller related functions into separate JavaScript file . And invoked this JavaScript file where I need message related functionalities.
Let us say that JS as Message.JS . In Message.JS I have used the app variable(Instantiated app from the JS Specific to the page globally).
JS specific to that page
var app = angular.module('appname',[]);
app.controller(...)
Message.JS
I have used the same app in my message.JS since message controller falls under that app.
app.service(...)
app.controller('messagecontroller',[]...)
When ever I need to invoke a function inside MessageController I will use Broadcast in angular to achieve this.For more info http://www.dotnet-tricks.com/Tutorial/angularjs/HM0L291214-Understanding-$emit,-$broadcast-and-$on-in-AngularJS.html
Regards,
Selvam.M
I've just started using AngularJs.
I need to use the SunCalc module to calculate sun positions for my app.
I have no idea on how to integrate the file to the app and how to access his different functions while respecting the AngularJs structure. Where to put the file? How to call a function? etc...
Here is a link so you can quickly see the structure of the SunCalc module and hopefully help me.
https://github.com/mourner/suncalc/blob/master/suncalc.js
Thanks a lot for your help!
Since this library exposes global SunCalc object with bunch of methods, what you can do is simply wrap this lib into custom service.
app.factory('SunCalc', function() {
return window.SunCalc;
});
Then you could use it like this in controller:
app.controller('MainCtrl', function($scope, SunCalc) {
$scope.position = SunCalc.getTimes(new Date(), 52.3667, 4.9000);
});
In this case you can event add your own methods to this service without messing with original library.
Note, that technically you could use globally accessible SunCalc without creating one more service for this. However using services offers sertain advantages: you can rename it easily, it allows to facade original library API, using global variables error-prone, etc.
Also remember to include script tag before Angular script tag.
Demo: http://plnkr.co/edit/rbATLGfGE2kx32tmEEoX?p=preview
I have a problem pretty much similar than the issue exposed in this question (AngularJS : Initialize service with asynchronous data). My difference is that I'm using angularAMD to load scripts asynchronously and I just can't fit the approaches above in the following app.config:
define(['angularAMD'], function (angularAMD) {
var app = angular.module('app', []);
app.config(['$routeProvider', function ($routeProvider) {
// some code here
}]);
app.run(['srvRules', function (srvRules) {
srvRules.getRules().then(function (result) {
// I need to bootstrap only after I get the rules from the server
});
}]);
return angularAMD.bootstrap(app);
});
EDIT 1
This is the approach I'm trying to accomplish: https://stackoverflow.com/a/21189057/2407203
EDIT 2
Adding more information: I have a webapi as the backend, it is a legacy system which provides all kinds of business rules needed to set up the application. The main information provided at this moment are:
I use $translateProvider(http://angular-translate.github.io) to dinamically load the dictionary with the current culture. All the texts should be taken from this dictionary.
I have a service that monitors all route changes and allows or restricts the access based on the rules returned.
Some information should be placed on the screen based on the rules. Those information are all encapsuled inside a directive on the initial html.
Some html controls may appear or not based on the rules as well.
There's really no easy or elegant way out. I ended up doing the following:
Started using ui-router(https://github.com/angular-ui/ui-router) instead of ngRoute;
Created a root abstract state, parent of all other states;
Used the resolve section of the root state to load all data needed before any controller get instantiated
I am new to angular.js and currently writing my first project.
Currently my controllers look like this, for example:
function MyCtrl($scope, MyService) {
$scope.foo = MyService.doStuff();
}
They work just fine that way (so far), but I browsed the source of another AngularJS application and noticed they're using angular.module to create their controllers.
Why, if at all, would I want to do this in my own application?
If you have multiple angular applications on your page and they have controllers with the same name you'll need to use module.controller to avoid conflicts. The same if you want to avoid pollute the global namespace