I am able to lazy load angularjs with the help of requirejs. But, how can I load modules that needs to be associated to the controller?
My example configuration in app.js looks like the following, loading all the providers and keeping a reference.
var app = angular.module('myApp', ['ui.router'])
var cacheProviders = {};
app.getProvider = function () {
return cacheProviders.$provide;
}
app.getCompileProvider = function () {
return cacheProviders.$compileProvider;
}
app.getControllerProvider = function () {
return cacheProviders.$controllerProvider;
}
app.getFilterProvider = function () {
return cacheProviders.$filterProvider;
}
app.config(['$stateProvider', '$urlRouterProvider', '$controllerProvider', '$compileProvider', '$filterProvider', '$provide',
function ($stateProvider, $urlRouterProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) {
(function () {
cacheProviders.$controllerProvider = $controllerProvider;
cacheProviders.$compileProvider = $compileProvider;
cacheProviders.$filterProvider = $filterProvider;
cacheProviders.$provide = $provide;
})();
var lazyCtrlLoad = function (controllerName) {
return ["$q", function ($q) {
var deferred = $q.defer();
require([controllerName], function () {
deferred.resolve();
});
return deferred.promise;
}];
}
$stateProvider.state('main.view2b', {
url: '/view2b',
templateUrl: 'forms/empl/searchEmplForm.html',
controllerAs: 'srchC',
controller: 'searchEmplCtrl',
resolve: {
loadOtherCtrl: lazyCtrlLoad('searchEmplCtrl')
}
})
In my other module, I am trying to register controllers, load services..
define([
'angular', 'angularResource'
], function (angular) {
angular.module('myApp')
.getControllerProvider()
.register(ctrl, ...)
But, while loading service below, I need access to $resource which is part of ngResource module in angularResource.
angular.module('myApp')
.getProvider().service('deptService', ['$resource', function ($resource) {
return $resource('/dept/:dept', {dept: '#_dept'});
}])
How can I load ngResource while initalizing the javascript controllers/services lazily?
Take a look to AngularAMD here. It allows you to load controllers in the ui-router without using lazyload. This AngularAMD is used to integrate requireJs and Angular.
$stateProvider
.state('home', {
url: '',
views: {
'#': angularAmd.route({
templateUrl: 'ngApplication/application/shared/layouts/basic/basicTplView.html',
controllerUrl: 'ngApplication/application/shared/layouts/basic/basicTplCtrl.js',
controller: 'basicTplCtrl'
}),
'header#home': angularAmd.route({
templateUrl: 'ngApplication/application/shared/layouts/header/headerView.html',
controllerUrl: 'ngApplication/application/shared/layouts/header/headerCtrl.js',
controller: 'headerCtrl'
})
},
});
Also, you are using requirejs, you can load all the dependencies for an specific controller using the define syntax of requireJs. Let's say you want to create a loginCtroller in a separately file, and this controller depends on another angular service:
define(['app', 'transformRequestAsFormPostService'], function (app) {
app.controller('loginCtrl', ['$scope', '$rootScope', '$sce', '$http', '$state', 'transformRequestAsFormPostService', function ($scope, $rootScope, $sce, $http, $state, transformRequestAsFormPost) {
$scope.login = function () {
/*do something here using the service*/
};
}]);
});
Here, the dependency called transformRequestAsFormPostService is another file, I defined it in the main.js (requireJs confifguration file) and it's defined using the same approach than the loginCtrol. Now I am using it in my project and its working so far so good.
Regards,
Ernesto
Related
I'm getting unknown provider error when i'm trying to use resolve from a state. The object i want returned seems to be returned correctly, so i can't really figure out what the problem is.
This is my first angular project so if I something seems wierd it probably is.
The error: https://docs.angularjs.org/error/$injector/unpr?p0=boardProvider%20%3C-%20board%20%3C-%20AppCtrl
var ponk = angular.module("ponk", ["ui.router", "ngResource"]);
ponk.config(['$stateProvider', '$urlRouterProvider',
"$locationProvider", function ($stateProvider, $urlRouterProvider,
$locationProvider) {
$locationProvider.html5Mode(true);
$urlRouterProvider.otherwise('/');
$stateProvider.state('board', {
url: '/b/:slug',
templateUrl: 'views/board.html',
controller: "AppCtrl",
controllerAs: "pk",
resolve: {
board: function($stateParams, boardFactory) {
var board = {};
if($stateParams.slug) {
board = boardFactory.get({slug:$stateParams.slug}).$promise;
}
return board;
}
}
});
}]).run(function($state) { $state.go('board'); });;
ponk.factory("boardFactory", ["$http", "$resource",
function($http, $resource) {
return $resource('/board/:slug', {slug:'slug'}, {update: { method: "PUT" }});
}]);
ponk.controller("AppCtrl", ["$scope", "$http", "boardFactory", "board",
function($scope, $http, boardFactory, board ) {
console.log(board); // correct object, but error
}]);
EDIT:
discovered the above code works. The problem is when i add this to the controller:
var pk = this;
var pk.board = board;
I have a basic angular setup. I want to add another factory service so that the mainCtrl can use it.
Here is my controller.js
angular.module('Manalator.controllers', [])
.controller('MainCtrl', ['$scope', function ($scope, manaFactory) {
manaFactory.testString();
}]);
Here is my services.js
angular.module('Manalator.services', [])
.factory('cordovaReady', [function () {
return function (fn) {
var queue = [],
impl = function () {
queue.push([].slice.call(arguments));
};
document.addEventListener('deviceready', function () {
queue.forEach(function (args) {
fn.apply(this, args);
});
impl = fn;
}, false);
return function () {
return impl.apply(this, arguments);
};
};
}])
.factory('manaFactory', [function(){
this.testString = function(){
return 'This works';
};
}]);
Here is my routes.js
angular.module('Manalator', ['ngRoute', 'Manalator.services', 'Manalator.controllers'])
.config(function ($routeProvider) {
$routeProvider
.when('/', {
controller: 'MainCtrl',
templateUrl: 'partials/pages/main.html'
})
.when('/devotion', {
controller: 'MainCtrl',
templateUrl: 'partials/pages/devotion.html'
})
.when('/results', {
controller: 'MainCtrl',
templateUrl: 'partials/pages/results.html'
})
.otherwise({redirectTo: '/'});
});
I get the following error:
TypeError: Cannot read property 'testy' of undefined
at new <anonymous> (controllers.js:3)
at Object.i [as invoke] (main.min.js:1)
at $get.f.instance (main.min.js:2)
at m (main.min.js:1)
at s (main.min.js:1)
at $get.e (main.min.js:1)
at main.min.js:1
at p.$get.p.$eval (main.min.js:3)
at p.$get.p.$apply (main.min.js:3)
at main.min.js:1
It is a cordova phonegap setup with basic routes. I am new to angular. I have looked over the internet and im having trouble setting up a basic service to hold all my data so i can access it from all my routes. Any help would be appreciated.
You will need to identify your services as a dependency of the controller.
The first step is to make sure you define the services before the controller.
then change the controller code so that it names the services as a dependency.
angular.module('Manalator.controllers', ['Manalator.services'])
.controller('MainCtrl', ['$scope', function ($scope, manaFactory) {
manaFactory.testString();
}]);
Hope this helps!
I am trying to lazy load my controllers for my AngularJS app I built along side with requireJS. I have created a custom "lazyLoad" library that creates a resolve object in app.config() routes (also I am using ui-router). If I code the state (without my library) to look like so it works
define(['angular', 'lazyLoader', 'uiRouter'], function(angular, lazyLoader, uiRouter){
var app = angular.module('myApp', ['ui.router']);
app.config(function ($stateProvider, $urlRouterProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) {
window.lazy = {
controller: $controllerProvider.register,
directive: $compileProvider.directive,
filter: $filterProvider.register,
factory: $provide.factory,
service: $provide.service
};
$urlRouterProvider.otherwise('/');
$stateProvider
.state('campaigns', {
url:'/campaigns',
views: {
"top-nav" : {
templateUrl: 'views/home/top-nav.html',
resolve : {
load : ['$q', '$rootScope', function($q, $rootScope){
var d = $q.defer();
require(['../app/controllers/header-controller'], function() {
$rootScope.$apply(function(){
d.resolve();
});
});
return d.promise;
}]
}
},
"fullpage": {
templateUrl: 'views/home/index.html',
resolve : {
load : ['$q', '$rootScope', function($q, $rootScope){
var d = $q.defer();
require(['../app/controllers/home-controller'], function() {
$rootScope.$apply(function(){
d.resolve();
});
});
return d.promise;
}]
}
//controller: 'home-controller'
}
}
});
});
return app;
});
If I attempt to replace the resolve object with my library function it looks would look like this:
define(['angular', 'lazyLoader', 'uiRouter'], function(angular, lazyLoader, uiRouter){
and
.state('home', lazyLoader.route({
url:'/',
views: {
"top-nav" : {
templateUrl: 'views/home/top-nav.html',
controllerUrl: '../app/controllers/header-controller'
},
"fullpage": {
templateUrl: 'views/home/index.html',
controllerUrl: '../app/controllers/home-controller'
}
}
}));
lazyLoader.js
define(function () {
'use strict';
function LazyLoader() {}
LazyLoader.prototype.route = function(config){
var controllerPath;
if(config && config.views){
var singleView = Object.keys(config.views);
for(var i in singleView){
var viewName = singleView[i];
controllerPath = config.views[viewName].controllerUrl;
delete config.views.controllerUrl;
config.views[viewName].resolve = {
load : ['$q', '$rootScope', function($q, $rootScope){
var d = $q.defer();
require([controllerPath], function() {
$rootScope.$apply(function(){
d.resolve();
});
});
return d.promise;
}]
};
}
}
return config;
}
return new LazyLoader();
});
Example Controller
define(['app/module'], function (module) {
lazy.controller('header-controller', ['$scope', function ($scope) {
// stuff here
}]);
});
On a side note I plan on implementing something better than attaching lazy variable to window.
When I code the router like the first example it works. When I use my lazyLoader the one of the two views loads it's controller, the second view's controller's file is started to load (console.logs at the beginning show this) but it cannot resolve "module" in the example above.
link to error: AngularJS Error
Again this issue only happens when using my lazyloader which is producing the same resolve object that I have hard coded in for the version that works.
I have searched high and low and there are a lot of resources out there but I could not find anything that addressed this issue.
Any advice is appreciated!
You are taking too much pain to do lazy loading of controllers & services. There is simple approach to lazy load files with ocLazyLoad. This article might help you resolve the same issue.
https://routerabbit.com/blog/convert-angularjs-yeoman-spa-lazyload/
What you should do is
Add a reference of ocLayzLoad & updated JS files’ reference to load on demand from app.js or .html file of their views.
`bower install oclazyload --save-dev`
Now load the module ‘oc.lazyLoad’ in application. Update app.js file
angular
.module('helloWorldApp', [
'ngCookies',
'ngResource',
'ngRoute',
'ngSanitize',
'oc.lazyLoad',
])
Load JS file by adding reference of JS in .html file
<div oc-lazy-load="['scripts/controllers/about.js', 'scripts/services/helloservice.js']">
<div ng-controller="AboutCtrl as about">
Your html goes here
</div>
</div>
If you using Grunt, update Gruntfile to uglyfy, renamed file name & update references in the final .html or .js file.
On the 'myApp' module definition, shouldn't you be returning app variable instead of myApp?
And to avoid exposing lazy to window, you could define it as a property of app variable, this way when you define new functions, you require app first and you can use it:
app.js:
app.lazy = {
controller: $controllerProvider.register,
directive: $compileProvider.register,
filter: $filterProvider.register,
factory: $provide.factory,
service: $provide.service
};
...
return app;
controller.js:
define(['app'], function (app) {
app.lazy.controller('header-controller', ['$scope', function ($scope) {
// stuff here
}]);
});
Hi I have following module, route and controller defined in one file called main.js
var mainApp = angular.module("mainApp", ["ngRoute", "ngResource", "ui"]).
config(function ($routeProvider) {
$routeProvider.
when('/addEmp', { controller: EmpCtrl, templateUrl: 'addEmp.html' }).
when('/addLoc', { controller: LocCtrl, templateUrl: 'newLocation.html' }).
otherwise({ redirectTo: '/' });
});
mainApp.factory("addEmp", ['$resource', function ($resource) {
return $resource('/api/addEmp/:id', { id: '#id' }, { update: { method: 'PUT' } });
}]);
mainApp.factory("addLoc", ['$resource', function ($resource) {
return $resource('/api/newLoc/:id', { id: '#id' }, { update: { method: 'PUT' } });
}]);
//Controllers
var EmpCtrl = function ($scope, $location, addEmp) {
//code here
};
var LocCtrl = function ($scope, $location, newLocation) {
//code here
};
What I am trying to do is organize this one file code into different files. I created script/controller folder where I want to have individual files for controller like
EmpCtrl.js and LocCtrl.js.
When I created the controller files and copied the controller code in it i get error of EmptCtrl and LocCtrl not defined.
Can you please tell me how I can set it up in different folders with appropriate path settings?
Thanks
try this
angular.module("mainApp", ["ngRoute", "ngResource", "ui"]).
config(function ($routeProvider) {
$routeProvider.
when('/addEmp', { controller: 'empCtrl', templateUrl: 'addEmp.html' }).
when('/addLoc', { controller: 'locCtrl', templateUrl: 'newLocation.html' }).
otherwise({ redirectTo: '/' });
});
//in empCtrl.js file
angular.module('mainApp').controller('empCtrl', ['$scope', '$location', 'addEmp',
function ($scope, $location, addEmp) {
//code here
}]);
// same for locCtrl
In your html make sure to include your mainApp.js file before you empCtrl and locCtrl scripts
the key is that you use string names to refer to your controller in your rout configs
{ controller: 'empCtrl' ... }
instead of
{ controller: EmpCtrl ... }
I would recommend that you use require.js to modularize your Angular project, you won't have to worry about order of script includes and it will result in a cleaner project
I want to reuse link.
How to use $routeProvider and custom module in config function?
angular.module('urls', []).
factory('$urls', function (
$location
) {
var $urls = {};
$urls.login = function () {
var url = '/login';
return url;
}
return $urls;
});
angular.module('app', ['urls']).
config(function ($routeProvider, $urls) {
$routeProvider.
when($urls.login(), { controller: PageCtrl, templateUrl: 'tem.html' }).
otherwise({ redirectTo: $urls.login() });
});
As I commented you can create a provider instead of a factory and put the URLs in that as the central place:
angular.module('urls', []).
provider('urls', function (){
this.$get = function(){
var obj = {}
obj.login = function(){ return '/login';}
//more urls here, you don't really need function though
return obj;
}
});
angular.module('app', ['urls']).
config(function ($routeProvider, urlsProvider) {
$routeProvider.
when(urlsProvider.login(), { controller: PageCtrl, templateUrl: 'tem.html' }).
otherwise({ redirectTo: urlsProvider.login() });
});
However, you can not inject the $location service to the urls provider. But if you really want to use $location, you can create another service that uses both the urls service and $location service to achieve the same effect like this:
angular.module('urls', []).
service('myUrlService', function (urls, $location){
this.goToLogin = function(){$location.path(urls.login());}//just an example
});
Then you can inject myUrlService to your controllers and do things like this:
myUrlService.goToLogin();