How to add multiple controllers to one view in Angular JS route - javascript

For example, in this official tutorial, only ONE controller PhoneListCtrl is assigned to the view /phones. What if I have multiple controllers for this view?
phonecatApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/phones', {
templateUrl: 'partials/phone-list.html',
controller: 'PhoneListCtrl'
}).
Thanks in advance!

There are plenty of ways to attack this concern.
You can use the ng-controller directive within a view:
<div ng-controller="someOtherController">
<input ng-model="propertyOfSomeOtherControllersScope" />
</div>
You can use the angular-ui team's ui-router module. In short, this allows you to have multiple named views within a single "state", which are idiomatically like their "routes". Way too much going on with it to describe it in full here, but it's a great module for almost any project.
This is kind of the same as the first solution, but you could use ng-include to include another partial which explicitly declares its controller. Basically, in your main file: <div ng-include="'file2.html'"></div> and in file2.html: <div ng-controller="someOtherController"></div>.
These three things just jump right to mind, there are certainly other ways to go about this. And in some cases, you might want a directive instead of just another controller within a single view. Hopefully this gets you started in the right direction.

Related

Controllers in AngularJS and templates

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.

Implement a logical part as Generic one in AngularsJs

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

Can I link an external javascript file to an AngularJS controller?

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()
}]);

Misunderstanding of Single-Page Routing in Angular

I think I have a fundamental misunderstanding about the way angular intercepts my routes in a single-page application.
My problem, I think, is pretty simple. When I enter the url:
localhost:3000/streams/
I would like to load the 'streams' page. The way I thought it works is as follows:
My express server receives the request, and answers with a layout.
app.get('/streams/',function(req,res){
res.render('layout');
})
My layout page is rendered. It calls a client app.js and has ng-view.
Angular intercepts the '/streams/' path, and then makes a call for the 'streams' template. Like this:
$routeProvider
.when('/',
{
templateUrl: '/templates/mainpage'
}
)
.when('/streams/',
{
templateUrl: '/templates/streams'
}
)
For some reason, reality is very very different.
When I load '/streams', angular retrieves /templates/streams, and
when I load '/streams/, angular retrieves /templates/mainpage.
Why?
This misunderstanding has been trolling me for days now...
Any help will be rewarded with 5 quanta of good energy.
Thanks.
It turns out that the real issue was a little different.
It's not, as was described, that Angular didn't know that I'm referring to 'streams', when I load 'streams/', it's that html had a relative base.
Basically, this relative base made it seem as though I have already found a template, namely, '/streams', and am now retrieving another one, namely, '/'. This issue can be simply resolved by adding the root base in your html.
<base href="/">
This should do it.

Angular sub-views

I google a bit about the topic but I couldn't get a clear answer on the subject, so apologies if this seems a pretty beaten down question. I've started with Angular not long ago, and I really want to be on the good path.
The application is bootstraped by app.js which defines the routes in the configuration. The index.html has a body with a ng-app directive an just a div inside with a ng-view.
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainController'
})
.otherwise({
redirectTo: '/'
});
This main.html and controller are the bulk of the app, which is quite simple.
Now I wanted to have a header, which either shows Login or the information from the user. I though that should be another Controller and another View, since the header should encapsulate all that code instead of polluting the main view.
What should I do?
I could remove the ng-app and create two different controllers for the header and the main app, but then I don't know how to associate each view to each ng-controller like the routeProvider is doing, although if I don't mind writing all the html inline, this should work. I would also lose routing which I don't really want to.
I could just create a ng-controller=headerController inside the app and still have the code inline. Is there an option to associate a template with a controller without the route definition?
What I'm currently going to do until I have a better option is to add all of this logic to the mainController. I just feel that I'm building big blocks instead of small ones that I can just compose. Imagine I do three more routes that need a header. Using option 1) or 2) I would have to write the template html for the header again in those views.
I would appreciate any links or help for this matter, I'm really curious how to approach this in a module fashion.
Thank you in advance.
I could remove the ng-app and create two different controllers for the header and the main app, but then I don't know how to associate each view to each ng-controller like the routeProvider is doing, although if I don't mind writing all the html inline, this should work. I would also lose routing which I don't really want to.
You will just write two different modules which have the same routeConfig and things will probably work. However, I do not think that it is the best solution in this case.
To answer your second question:
I could just create a ng-controller=headerController inside the app and still have the code inline. Is there an option to associate a template with a controller without the route definition?
You can use ng-include to include the template:
<body ng-app="MyApp">
<section ng-include="'header.html'" ng-controller="HeaderController"></section>
<ng-view></ng-view>
</body>
Moreover, you can keep the template inline by using either the $templateCache or by using <script> tag.
You can use ng-include to insert your template. I personally like to use ui-router

Categories

Resources