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
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 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.
Is it possible to have multiple controllers on one route / page. I want to show 2 features of my application on one page. But they are not directly related so each would need it's own controller, model and (partial) view.
But I can't seem to figure out how I could do this.
It seems that I must use the {{render}} option here.
Is it possible to have a subdirectory structure here?
When I have {{render "dashboard.users"}} for the template it does look in template/dashboard/users.hbs but for the controller I can't seem to find where it looks and what the naming conventions should be.
E.g. should it be
App.DashboardUsersController = ... ?
edit:
Looks like it should be, but I shouldn't place it in a subfolder of controllers but name it dashboard_users_controller.js
You get this effect by rendering templates into multiple outlets of their parent template: Guide and API Docs
Here is a running JSBin demonstrating it
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.
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.