I have a controllers folders in www/js/controllers where I keep all the controllers needed by my app. But when I start the app all the controllers are loaded at once. Now how can I load only those controllers whose view is being used and keep other controllers at peace.
To dynamically load controllers, you need to use RequireJS.
http://requirejs.org/
Using https://oclazyload.readme.io/docs/with-your-router
Or,
Try this:
If you are using ngRoute:
$routeProvider
.when('/url',
{
templateUrl: '/views/abc.html',
resolve: resolveController('/controllers/abc.js')
});
Using UI-Router:
.state('abc',{
url : '/abc',
templateUrl : 'views/abc.html',
resolve: resolveController('/controllers/abc.js')
})
I don't know what you are trying to ask exactly.
See, JavaScript load All files(even won't take much time) while execute the app. Note it, files load only(allocate the memory) not execute the function except on-fly function. Ex (Angularjs, Jquery, Underscore - the file load first time only but function execute when we use).
Angularjs is JS framework right?. So same like above, here we are telling to execute controller in routing or ng-controler directive as per view, Note the file was loaded before only. In single view we can execute many controllers(ng-controller) as per need.
Create Controllers & Services in IIFE based. It's good.
Related
I am trying to make a single page app where I want to load screens (partial views) via ajax. The problem is that the user want's to open the same screen multiple times (in tabs). I tried to load the controller code on initial load and loaded my screens (partial views) via AJAX. But the controller is already executed by the time the screen (partial view) is loaded.
I want to know how to make controller run after the partial view is loaded?
Or better yet, how to tackle this situation where i want to load the same view multiple time with different data/state?
I found a solution to the problem I was facing. I am not sure if it is the best way to move forward but given the limited knowledge I have on AngularJS so far, this solution is my best bet. If anyone can come up with a better solution, I am all ears.
Instead of registering controller up front, I am registering the controller when the view is requested.
Also, I am appending a new div to the container where I want the view to appear. There is some jQuery on the page that hides other views and only shows the current view.
Step 1
Assigned $controllerProvider.register to a variable on App Scope
var myApp = angular.module("myApp", []);
angular.module("myApp").config(function ($controllerProvider) {
myApp.registerCtrl = $controllerProvider.register;
});
Step 2
In the function where I have to load the view dynamically, I did the following
$("#viewContainer").append($compile('<div ng-include="pageUrl"></div>')($scope));
The above line adds a div with ng-include directive. It also compiles the directive. The pageUrl is where I am keeping the url to the view I want to include.
Step 3
In the view file I have to load, I have include JavaScript file that holds my controller. The rest of the file contains simple HTML with directives. In the JS file, instead of creating the controller, I am registering the controller like
angular.module('myApp').registerCtrl("MyController", MyController);
I hope this is helpful to others.
app.config(function($routeProvider) {
$routeProvider
// route for the home page
.when('/demo', {
templateUrl : 'assets/pages/home.html'
})
// route for the sport page
.when('/sport', {
templateUrl : 'assets/pages/sport/home.html',
controller : 'sportController'
});
// route for the sport page
.when('/television', {
templateUrl : 'assets/pages/television/home.html',
controller : 'televisionController'
});
});
I have sportControllerin a file called SportCtrl.js and televisionController in a file called TvCtrl.js, how would I be able to load this into my view while using Routing?
You should correctly add your controller in app namespace and Angular does all things themselves.
For example, working structure for project:
Load Angular, dependencies.
Load your application initializer, configs.
Load other stuff like controllers, directives, services, filters.
Example of controller code:
app.controller('sportController', ['$scope', function($scope){
}])
BTW, for Angular file name means nothing.
You are trying to do a lazy loading of javascript files. This is not an Angular functionality, you have 3 solutions:
use requireJs to load files on-the-fly.
include all your javascript files in html
concatenate all the javascript files in only one file.
I prefer not to use requireJS to prevent one more inclusion and configuration :-)
I previously thought that the controller script would only be executed once, when my single page application is loaded.
Now I see that every time I change a view my controller script executes again. I can tell because i had a couple of statements in the script that are not nested in functions. I want them to happen only when the app is first loaded, but they are running when I change views.
The views are configured in my app.js with module.config:
myModule.config(function ($routeProvider) {
$routeProvider
.when('/search', {
templateUrl: 'views/search.html',
controller: 'searchCtrl'
})
.when...
So, is it normal for the controller script to run when the view changes? Or should I be searching for something I have configured wrong?
Yes this is normal. It was(/is) the same for me, however I use angular-ui-router... The solution I chose in order to make sure that the data in the controller would persist was to use a factory, you could use a service or provider just as well.
"Specialized objects conform to a specific Angular framework API. These objects are one
of controllers, directives, filters or animations.
The injector needs to know how to create these objects. You tell it by registering a
"recipe" for creating your object with the injector. There are five recipe types.
The most verbose, but also the most comprehensive one is a Provider recipe. The
remaining four recipe types — Value, Factory, Service and Constant — are just
syntactic sugar on top of a provider recipe."
https://docs.angularjs.org/guide/providers
Background: Let's suppose for the sake of argument that you have 100,000 views (partials). Let's also suppose you have accompanying view-scoped controllers, and potentially view-scoped services and filters as well. Try to envision an aggregating application that hosts 100,000 disparate small applications.
Issue: When you have "partials" that require accompanying controllers, the typical solution is to do something like this:
$routeProvider.when('/app1', {
templateUrl: 'partials/view1.html',
controller: 'controller1'
});
The controller is typically loaded from index.html via:
<script src="js/directives/Controller1.js"></script>
The problem with this approach is that it doesn't scale. There are solutions out there for dynamically loading controllers, but they still require adding touch points in various config.
Ideal Solution: Ideally - again for very small applications whose numbers are in the 000's, the controller could be loaded dynamically, and from within the partial itself. This would alleviate the need to manage several files and several configuration touch points (not to mention network requests), and keep each partial very well contained.
It would look something like this:
In router:
$routeProvider.when('/apps/:appId', {
templateUrl: 'partials/app-frame.html',
controller: 'AppCtrl'
});
In containing html (app-frame) include the relatively disparate "mini app":
<h1>Currently hosting {{appId}}</h1><hr>
<div class="ng-include: appUrl"></div>
In partial resolved with appUrl, define controller and markup in one:
<script>
myApp.controller('controller1', ['$scope', function ($scope) {
$scope.foo = "bar";
}]);
</script>
<div ng-controller="controller1">
{{foo}}
</div>
For cases like this, where there are a lot of partials and a 1-1 mapping for controller and view, it can make sense to couple the two for development efficiencies and maintenance. It's a lot cleaner than using several files and additional configuration touch points.
The problem is, this doesn't work. It could be as simple as forcing the script to load prior to applying the directive... but not sure how to do that?
Here are some similar explanations of the problem:
https://groups.google.com/forum/#!topic/angular/H4haaMePJU0
Loading Partial Page With Angular and Compile The Controller
Igor from the AngularJS team says:
I see.. we looked into supporting script tags in jqlite, but what needs to be done to get a cross-browser support involves a lot of black magic. For this reason we decided that for now we are just going to recommend that users use jquery along with angular in this particular case. It doesn't make sense for us to rewrite one third of jquery to get this working in jqlite.
But I don't know what he means by "use jquery" ... JQuery is already loaded into the application from index.html (and prior to angularjs), but it sounds like I need to do something specifically within the partial itself.
You cannot add new controllers through module('app').controller(name, function() { .. }) after AngularJS bootstrap. In order make it work you should use $controllerProvider.register(name, function() { .. }).
You can override the original controller registering function in following way to be able to add controllers pre and pos bootstrap:
var app = angular.module('app', [
'ui.router'
]);
app.config(function($controllerProvider) {
app.controller = function (name, controller) {
$controllerProvider.register(name, controller);
};
});
I'm using an angularJS and requireJS seed which you can download here: LINK
In that seed only the controllers that are called download the relevant controller which is then triggered. I've been trying to call a factory from my controller (with no luck) plus I would like the services/factories only to download the relevant factory if it has been called.
I've attempted to require a function within the factory method (much like the controller) but it is not working.
This is where I left off: Plunkr link
user971824.
I've put together something I call couchPotato that lazy-registers just about anything in angular using requirejs and the resolution features of $routeProvider (or any other router that does lazy promise-based resolution.
I've created a plunker based on yours demonstrating how you could do it with couchPotato. If you take a look at it, I think you'll see that it's a bit simpler because you don't actually create modules for all of the things you register lazily.
couchPotato grew out of some other example apps I found on the web. What I wanted was a tight way to do the lazy registration and a provider/service combo seemed ideal. I also wanted to maintain the ability for one component to depend on another, like in your example, you want the controller to depend on the factory... couchPotato lets you specify those dependencies in requirejs syntax.
So your controller, in my rendition, looks like this:
define(['app', 'myFactory'], function(app) {
app.couchPotato.registerController([
'mycontroller',
[
'myFactory',
function(myFactory) {
var message = myFactory.getCustomers();
alert(message);
}
]
]);
});
In this example, I made the controller, the factory and the value all lazy, but you could pick and choose and have some registered the "old fashioned way" at configuration time and others registered with couchPotato when they're needed for a given route.
http://plnkr.co/edit/Z3v1mszQiiq024po8Ocp?p=preview
A couple of things to note:
1) I put in a default route in order to trigger the lazy loading of your controller, your service (factory) and the version value.
2) I modified your service to append the version just to show how one component can depend on another (the service depends on the version value, the controller depends on the service).
So, within the require configuration, you don't actually specify any of this... it's all done lazily within your route.
$routeProvider.when('/',
$couchPotatoProvider.resolveDependenciesProperty({
templateUrl:'home.html',
controller: 'mycontroller',
dependencies: [
'mycontroller'
]
})
);
Since mycontroller depends on myFactory and myFactory depends on version, by the time your route is displayed they are all available and hooked up. I put some dummy text in the home.html partial just for kicks, but the controller is assigned by the $routeProvider so you don't actually need to specify it in the template.
couchPotato lives at https://github.com/afterglowtech/angular-couchPotato if you'd like to see a couple of other samples. I shim'ed it in dependent on angular because I designed it to be usable in cases where an entire application doesn't necessarily use requirejs... thus if you are loading angular with requirejs, you need to make couchPotato dependent on angular using the shim/deps technique.
LMK if you have any questions/comments... hope this helps!