Angular controller scope/variables not appearing - javascript

I'm trying to clean up my code such that it corresponds to John Papa's Angular style guide but in the process broke something and my controller no longer appears in ng-inspector. If I can get vm.message to display I can figure out the rest (though any general feedback is appreciated :))
(function () {
"use strict";
angular
.module('roomchoice.manager-dashboard.alerts', [
'ui.router'
])
.config(function config($stateProvider) {
$stateProvider.state('manager.alerts', {
url: '/alerts',
views: {
"main": {
controller: 'AlertsController',
templateUrl: 'manager-dashboard/alerts/alerts.tpl.html'
}
},
data: {
pageTitle: 'Alerts'
}
});
})
.controller('AlertsController', AlertsController);
function AlertsController($scope, Restangular) {
var vm = this;
vm.message = "Hello";
vm.settlements = [];
vm.undepositedPayments = [];
vm.unapprovedFunnels = [];
vm.getSettlements = getSettlements;
vm.getUndepositedPayments = get_UndepositedPayments;
vm.getUnapprovedFunnels = get_unapprovedFunnels;
function getSettlements() {
Restangular.all('alerts/get_settlements').getList().then(function(settlements){
vm.settlements = settlements;
return vm.settlements;
});
}//End of getSettlements
function getUndepositedPayments() {
Restangular.all('alerts/get_undepositedpayments').getList().then(function(undepositedpayments){
vm.undepositedPayments = undepositedpayments;
return vm.undepositedPayments;
});
}//End of getUndepositedPayments
function getUnapprovedFunnels() {
Restangular.all('alerts/get_unapprovedfunnels').getList().then(function(unapprovedfunnels){
vm.unapprovedFunnels = unapprovedfunnels;
return vm.unapprovedFunnels;
});
}//End of getUnapprovedFunnels
}//End of Controller
})();//End of Module
<div id="main" ng-controller="AlertsController as alerts">
<div>
<h1>Alerts (Under Construction) </h1>
<h2>{{alerts.message}}</h2>
</div>
</div>

You are trying to instantiate your controller more than once in your code, and this won't work the way you expect.
You should not use ng-controller in templates that are part of a state. The controller is defined by the state provider, and does not be instantiated inside the template.
Remove ng-controller from your template, and add controllerAs to your state:
$stateProvider.state('manager.alerts', {
url: '/alerts',
views: {
"main": {
controller: 'AlertsController',
controllerAs: 'alerts',
templateUrl: 'manager-dashboard/alerts/alerts.tpl.html'
}
},
data: {
pageTitle: 'Alerts'
}
});

Related

How to Initialize third party JavaScript asynchronous library before loading AngularJS

I'm facing problem while initializing a third party JavaScript API (iHUB) inside RUN method of AngularJS. Currently the code is behaving in asynchronous mode. I want IHUB to first initialize and then AngularJS route/controller should get called. (Is it possible to make utilization of the callback method provided by IHUB ?)
var nameApp = angular.module('nameApp', ['ngRoute']);
nameApp.run(['$window', 'myService', function($window, myService) {
//initialize IHUB
var actuate= new actuate();
actuate.initialize('http://localhost:8700/iportal', settings.reqOps, "user", "pwd", callback);
function callback(){
alert('started!!');
}
}]);
nameApp.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/:tabname', {
templateUrl: 'pages/analyticsDetail.html',
controller: 'tabDetailCtrl'
}).
when('/:tabname/:reportName', {
templateUrl: 'pages/analyticsDetail.html',
controller: 'reportDetailCtrl'
}).
otherwise({
redirectTo: '/Buy Side Dashboard'
});
}]);
There is only one way to achieve a "real" before AngularJS initialization behavior by using angular.bootstrap();. This allows you to initialize your AngularJS application manually.
Note: You should not use the ng-app directive when manually bootstrapping your app.
> Fiddle demo
View
<div ng-controller="MyController">
Hello, {{greetMe}}!
</div>
Application
angular.module('myApp', [])
.controller('MyController', ['$scope', function ($scope) {
$scope.greetMe = 'World';
}]);
var actuateDummy = {
initialize: function (callback) {
setTimeout(callback, 2500);
}
};
actuateDummy.initialize(function () {
angular.element(function() {
angular.bootstrap(document, ['myApp']);
});
})
This is an other approach which uses the resolve state of ui-router. This service only initializes iHUB if it not has been initialized yet:
This service also returns the actuate object. In that way you can use it in your controller or components after init.
> Demo fiddle
View
<nav>
<a ui-sref="state1">State 1</a>
<a ui-sref="state2">State 2</a>
</nav>
<div ui-view></div>
AngularJS Application
var myApp = angular.module("myApp", ["ui.router"]);
myApp.config(function($stateProvider, $urlRouterProvider) {
$stateProvider.state("state1", {
url: "#",
template: "<p>State 1</p>",
controller: "Ctrl1",
resolve: {
iHubInit: function(iHubService) {
return iHubService.init()
}
}
}).state("state2", {
url: "#",
template: "<p>State 2</p>",
controller: "Ctrl2",
resolve: {
iHubInit: function(iHubService) {
return iHubService.init()
}
}
});
});
myApp.controller("Ctrl1", function($scope, iHubService) {
console.log("Ctrl1 loaded.");
});
myApp.controller("Ctrl2", function($scope, iHubService) {
console.log("Ctrl2 loaded.");
});
myApp.service('iHubService', ["$q", function($q) {
this.iHubServiceInitialized = false;
this.actuate = null;
this.init = function() {
if (!this.iHubServiceInitialized) {
//Init
var self = this;
var deferred = $q.defer();
this.actuate = new actuate();
//initialize
this.actuate.initialize('http://localhost:8700/iportal', settings.reqOps, "user", "pwd", function() {
self.iHubServiceInitialized = true;
deferred.resolve(self.actuate);
});
return deferred.promise;
} else {
return this.actuate;
}
}
}]);
Try to add a resolve attribute when configuring your route provider like below:
var nameApp = angular.module('nameApp', ['ngRoute']);
nameApp.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/:tabname', {
templateUrl: 'pages/analyticsDetail.html',
controller: 'tabDetailCtrl',
resolve: {
ihubInit: ['iHubService', function (iHubService) {
return iHubService.init();
}]
}
}).
when('/:tabname/:reportName', {
templateUrl: 'pages/analyticsDetail.html',
controller: 'reportDetailCtrl',
resolve: {
ihubInit: ['iHubService', function (iHubService) {
return iHubService.init();
}]
}
}).
otherwise({
redirectTo: '/Buy Side Dashboard'
});
}]);
nameApp.service('iHubService', ["$q", function($q){
this.init = function() {
var deferred = $q.defer();
var actuate= new actuate();
actuate.initialize('http://localhost:8700/iportal', settings.reqOps, "user", "pwd", callback);
function callback(){
deferred.resolve();
}
return deferred.promise;
}
}]);

Angular service that is instantiated on every page change/request

So, I'm making my first steps in AngularJS (1.5) and I'm trying to build a feature that will let me change few things in my layout based on the route.
As far as I understood I needed a service for this. Basically the setup I have is:
'use strict';
/* App Module */
var app = angular.module('app', [
'ngRoute',
'appControllers',
'AppServices'
]);
app.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/', {
template: '<h1>Home page</h1>',
controller: 'MainController'
}).when('/page', {
template: '<h1>Page</h1>',
controller: 'PagesController'
}).otherwise({
redirectTo: '/'
});
}]);
var appControllers = angular.module('appControllers', []);
appControllers.controller('MainController', ['$rootScope', 'AppSetup', function($scope, AppSetup) {
$scope.app = AppSetup.build();
console.log('home');
}]);
appControllers.controller('PagesController', ['$rootScope', 'AppSetup', function($scope, AppSetup) {
AppSetup.setProperties({
meta: {
title: 'My Second Page'
}
});
console.log('page');
$scope.app = AppSetup.build();
}]);
var AppServices = angular.module('AppServices', []);
AppServices.service('AppSetup', [function() {
var properties = {
meta: {
title: 'My App • Best of the best'
}
},
styles;
this.setProperties = function(input) {
this.properties = angular.extend(properties, input);
};
//TODO: This will override app-wide styles.
this.setStyles = function(input) {
this.styles = angular.extend({}, input);
};
this.build = function() {
return {
properties: properties,
styles: styles
};
};
}]);
Plunkr here
So I have one defined properties object and want to override it when I visit a page. The problem is that when I go back to home, it doesn't set the default value. Obviously it's instantiated once the page is loaded and then remains the same until changed.
What's the best approach to do this?
I have tried adding a listener to the route, as #Raul A. suggested, but it's not working. Output from console:
Plunkr here
You can use the $routeChangeSuccess event if you are using routing and make changes in the function watching for it:
$rootScope.$on("$routeChangeSuccess", function(currentRoute, previousRoute){
//Do you changes here
});

ui-sref blocked from accessing controller data or view

I am having some trouble getting to the controller for my state param. I am using the correct state to link to the next view.
<td><a ui-sref="orders({customerId: cust.id})">View Orders</a></td>
In my config file I am referencing the state that name and the route params. I commented out the resolve object for now. My goal is to get into the controller then pass the correct data. Notice that I am using controllerAs
My initial thought was ({customerId: ctrl.cust.id }) However that did not change the url route.
The url is changing to match the url name but is not connecting to the controller and is not giving me the view.
(function() {
'use strict';
angular
.module('app.orders')
.config(config);
function config($stateProvider) {
$stateProvider
.state('orders',{
// params: {customerid: null},
url:'/customers:customerId',
templateUrl: './components/orders/orders.html',
controller: 'OrdersController',
controllerAs: 'ctrl',
resolve: {
customerFactory: 'customerFactory',
customerInfo: function( customerFactory, $stateParams) {
return customerFactory.getCustomers($stateParams.id);
}
}
************** my main problem is the resolve. This is blocking me from getting into the next controller. *****************
resolve: {
customerId:[ '$stateParams','customerFactory', function( $stateParams, customerFactory) {
return customerFactory.getCustomers($stateParams.id);
}]
}
})
};
})();
For now my controller is very small. I just want to connect to it. I have checked my networks tab and see GET for the files.
(function() {
// 'use strict';
angular
.module('app.orders')
.controller('OrdersController', OrdersController);
function OrdersController($stateParams) {
console.log('in');
var vm = this;
vm.title = "Customer Orders";
vm.customer = null;
}
}());
I have referenced my module in the main javascript file.
(function () {
'use strict';
angular.module('app', ['app.services',
'app.customers',
'app.orders','ui.router']);
})();
When I comment out the resolve I am able to access the controller. So I know the problem is in the resolve. Here is my service. I am making a request to a Json file with $http request and using .then
Updates Here is my refactored service call I am getting back the correct customer in the console each time.
(function() {
angular
.module('app.services',[])
.constant('_', window._)
.factory('customersFactory', customersFactory);
function customersFactory($http, $log) {
return {
getCustomers: getCustomers,
getCustomer: getCustomer
};
function getCustomers(){
return $http.get('./Services/customers.json',{catch: true})
.then(getCustomerListComplete)
.catch(getCustomerListFailed);
function getCustomerListComplete(response) {
console.log('response.data',response.data);
return response.data;
}
function getCustomerListFailed(error) {
console.log('error', error);
}
}
function getCustomer(id) {
var url = './Services/customers.json';
return $http.get(url, {
catch: true
})
.then(function(response) {
console.log('promise id',id);
var data = response.data;
for(var i =0, len=data.length;i<len;i++) {
console.log('data[i].id',data[i].id);
if(data[i].id === parseInt(id)) {
console.log('data[i]', data[i]);
return data[i];
}
}
})
}
}
}());
There is a working example with your code
It is very hard to guess what is wrong. Based on suggestion I gave you here Have a expression error in ui-sref ... your code seems to be completely valid.
I placed your stuff into this app.orders.js file (the ONLY change is templateUrl path, just for plunker purposes):
angular
.module('app.orders', ['ui.router'])
'use strict';
angular
.module('app.orders')
.config(['$stateProvider', config]);
//config.$inject = ['$stateProvider'];
function config($stateProvider) {
$stateProvider
.state('orders',{
// params: {customerid: null},
url:'/customers:customerId',
//templateUrl: './components/orders/orders.html',
templateUrl: 'components/orders/orders.html',
controller: 'OrdersController',
controllerAs: 'ctrl'
// resolve: {
// customerId:[ '$stateParams','customerFactory', function( $stateParams, customerFactory) {
// return customerFactory.getCustomers($stateParams.id);
// }]
// }
})
};
// 'use strict';
angular
.module('app.orders')
.controller('OrdersController', OrdersController);
OrdersController.$inject = ['$stateParams'];
function OrdersController($stateParams) {
console.log('in');
var vm = this;
vm.title = "Customer Orders " + $stateParams.customerId;
vm.customer = null;
}
And this is the working template components/orders/orders.html:
<div >
<h3>current state name: <var>{{$state.current.name}}</var></h3>
<h5>title</h5>
<pre>{{ctrl.title}}</pre>
...
When I call it like this:
<li ng-repeat="cust in [{id:1}, {id:2}]"
><a ui-sref="orders({customerId: cust.id})">View Orders - cust ID == {{cust.id}}</a>
</li>
Check it in action here
So, whil my previous answer was about make the state working without resolve, now we will observe few adjustments (and one fix) to make even resolve working.
There is a working plunker, extending the previous one.
FIX
The only fix, the most important change come from this definition:
angular
.module('app.services',[])
.factory('customersFactory', customersFactory);
see the plural in the factory name, the 'customersFactory'. While here:
...my main problem is the resolve. This is blocking me from getting into the next controller....
resolve: {
customerId:[ '$stateParams','customerFactory', function( $stateParams, customerFactory) {
return customerFactory.getCustomers($stateParams.id);
}]
}
we ask for 'customerFactory' (singular, no s in the middle)
Few improvements:
So, this would be our adjusted state def:
$stateProvider
.state('orders',{
// INTEGER is here used to later easily use LO_DASH
url:'/customers{customerId:int}', // int is the type
templateUrl: './components/orders/orders.html',
controller: 'OrdersController',
controllerAs: 'ctrl',
resolve: {
// wrong name with 's'
//customerId:[ '$stateParams','customerFactory',
// we use customer, because we also changed the factory
// implementation - to return customer related to
// $statePrams.customerId
customer:[ '$stateParams','customersFactory',
function( $stateParams, customersFactory) {
return customersFactory
//.getCustomers($stateParams.id)
.getCustomer($stateParams.customerId)
;
}]
}
})
Now, this is our adjusted factory, and its new method getCustomer
angular
.module('app.services', [])
.factory('customersFactory', customersFactory);
customersFactory.$inject = ['$http', '$log', '$q', '$stateParams'];
function customersFactory($http, $log, $q, $stateParams) {
return {
getCustomers: getCustomers,
getCustomer: getCustomer
};
function getCustomers() {
// see plunker for this, or above in question
}
// new function
function getCustomer(id) {
var url = "customer.data.json";
return $http
.get(url, {
catch: true
})
.then(function(response){
var data = response.data;
var customer = _.find(data, {"id" : id});
return customer;
})
;
}
}
this is our data.json:
[
{
"id" : 1, "name": "Abc", "Code" : "N1"
},
{
"id" : 2, "name": "Def", "Code" : "N22"
},
{
"id" : 3, "name": "Yyz", "Code" : "N333"
}
]
And here we have controller:
OrdersController.$inject = ['$stateParams', 'customer'];
function OrdersController($stateParams, customer) {
console.log('in');
var vm = this;
vm.title = "Customer Orders " + $stateParams.customerId;
vm.customer = customer;
}
a view to show customer
<h3>customer</h3>
<pre>{{ctrl.customer | json}}</pre>
Check it here in action

Updating $scope for ng-repeat after service

I have seperated out my controllers & services into modules, and on a form submit, I am trying to get data from a service and then set it in the scope, but I'm having trouble getting the view to update with the new data. I have gone through other questions with similar problems but I can't seem to get it working. The view updates fine from the Search.get() function, but not from the $scope.submitFilterForm function.
I'm trying to update like this:
$scope.searchDetails = results;
This is my code at the moment:
SearchCtrl.js
angular.module('SearchCtrl', []).controller('SearchController', function($scope, $http, Page, Search) {
$scope.pageClass = 'page-search';
$scope.showContent = false;
$scope.searchDetails = [];
Search.get().success(function(searchResults) {
$scope.searchDetails = searchResults;
Page.setTitle('Search');
$scope.showContent = true;
});
$scope.submitFilterForm = function(isValid) {
if (isValid) {
Search.filterByPostcode($scope.postcode, $scope.searchradius).success(function(results) {
console.log('results', results);
$scope.searchDetails = results;
});
}
}
});
SearchService.js
angular.module('SearchService', []).factory('Search', ['$http', function($http) {
return {
get: function() {
return $http.get('/api/places');
},
filterByPostcode: function(postcode, searchradius) {
return $http.get('/api/filter-by-postcode/'+postcode+'/'+searchradius);
}
}
}]);
search.html
<div class="places-list" ng-show="showContent">
<div class="places-list-item" ng-repeat="place in searchDetails">
{{place.place_name}}
</div>
</div>
I also have the template above set up in appRoutes.js like so:
$routeProvider
// home page
.when('/search', {
title: 'Search',
templateUrl: '/partials/search.html',
controller: 'SearchController'
})
$locationProvider.html5Mode(true);
Thanks for any help.

AngularJS: lazy loading controllers and content

In this simplified scenario, I have two files: index.htm, lazy.htm.
index.htm:
var myApp = angular.module('myApp', []);
myApp.controller('embed',function($scope){
$scope.embed = 'Embedded Controller';
});
<div ng-controller="embed">{{embed}}</div>
<div ng-include="'lazy.htm'"></div>
lazy.htm
myApp.controller('lazy',function($scope){
$scope.lazy = 'Lazy Controller';
});
<div ng-controller="lazy">
{{lazy}}
</div>
The result is an error: "Argument 'lazy' is not a function, got undefined"
Using a function instead
lazy.htm
function lazy($scope) {
$scope.lazy = 'Lazy Controller';
}
<div ng-controller="lazy">
{{lazy}}
</div>
This works until version 1.3 beta 14. In beta 15 was removed the global controller functions: https://github.com/angular/angular.js/issues/8296
So now, what is the better way to get angularized contents of lazy.htm dynamically?
UPDATE:
In this article (http://ify.io/lazy-loading-in-angularjs) I found another possible solution. The $controllerProvider allow us to register new controllers after angular bootstrap. Works like a charm. Tested in v1.3.0-beta.18
index.htm:
var myApp = angular.module('myApp', [])
.controller('embed',function($scope){
$scope.embed = 'Embedded Controller';
})
.config(function($controllerProvider) {
myApp.cp = $controllerProvider;
});
<div ng-controller="embed">{{embed}}</div>
<div ng-include="'lazy.htm'"></div>
lazy.htm
myApp.cp.register('lazy',function($scope){
$scope.lazy = 'Lazy Controller';
});
<div ng-controller="lazy">
{{lazy}}
</div>
UPDATE 2:
Two other alternatives that works are:
lazy.htm
_app = $('[ng-app]').scope();
_app.lazy = function($scope) {
$scope.lazy = 'Lazy Controller';
};
OR
var $rootScope = $('[ng-app]').injector().get('$rootScope');
$rootScope.lazy = function($scope) {
$scope.lazy = 'Lazy Controller';
};
But I believe these last two examples should not be used in production.
You can also use the jquery with the resolve the $routeProvider
app.js
/* Module Creation */
var app = angular.module ('app', ['ngRoute']);
app.config(['$routeProvider', '$controllerProvider', function($routeProvider, $controllerProvider){
/*Creating a more synthesized form of service of $ controllerProvider.register*/
app.registerCtrl = $controllerProvider.register;
function loadScript(path) {
var result = $.Deferred(),
script = document.createElement("script");
script.async = "async";
script.type = "text/javascript";
script.src = path;
script.onload = script.onreadystatechange = function (_, isAbort) {
if (!script.readyState || /loaded|complete/.test(script.readyState)) {
if (isAbort)
result.reject();
else
result.resolve();
}
};
script.onerror = function () { result.reject(); };
document.querySelector("head").appendChild(script);
return result.promise();
}
function loader(arrayName){
return {
load: function($q){
var deferred = $q.defer(),
map = arrayName.map(function(name) {
return loadScript('js/controllers/'+name+".js");
});
$q.all(map).then(function(r){
deferred.resolve();
});
return deferred.promise;
}
};
}
$routeProvider
.when('/', {
templateUrl: 'views/foo.html',
resolve: loader(['foo'])
})
.when('/bar',{
templateUrl: 'views/bar.html',
controller: 'BarCtrl',
resolve: loader(['bar'])
})
.otherwise({
redirectTo: document.location.pathname
});
}]);
/views/foo.html
<section ng-controller='FooCtrl'>
{{text}}
</section>
js/controllers/foo.js
/*Here we use the synthesized version of $controllerProvider.register
to register the controller in view*/
app.registerCtrl('FooCtrl',function($scope){
$scope.text = 'Test';
});
/views/bar.html
<section>
{{text2}}
</section>
js/controllers/bar.js
app.registerCtrl('BarCtrl',function($scope){
$scope.text2 = 'Test';
});
////JConfig file--------
window.angularApp.config(function ($routeProvider,$controllerProvider,$compileProvider,$provide, azMessages) {
$routeProvider.when('/login', {
resolve: {
load: ['$q', '$rootScope', function ($q, $rootScope) {
var deferred = $q.defer();
require([
//load required Js file here
], function () {
$rootScope.$apply(function () {
deferred.resolve();
});
});
return deferred.promise;
} ]
}
});
$routeProvider.otherwise({ redirectTo: '/login' });
window.angularApp.components = {
controller: $controllerProvider.register,
service: $provide.service,
directive: $compileProvider.directive
}
//contoller declaration
angularApp.components.controller('DiscussionController',[function(){
}]);
At first I utilized André Betiolo's answer. However, it does not always work becasue the ajax loading is non-blocking causing the view to sometimes request the controller prior to the script being loaded.
As a solution i forced the function not to return until all scripts successfully loaded. This is kind of hackish but makes sure the loads are successful prior to completing the resolve. It also allows for loading of multiple controllers.
app.js
var app = angular.module ('app', ['ngRoute']);
app.config(['$routeProvider', '$controllerProvider', function($routeProvider, $controllerProvider){
/*Creating a more synthesized form of service of $ controllerProvider.register*/
app.registerCtrl = $controllerProvider.register;
//jquery to dynamically include controllers as needed
function controllers(controllers){
var numLoaded = 0;
for (i = 0; i < controllers.length; i++) {
$.ajaxSetup({async:false});
$.getScript('js/controllers/' + controllers[i] + '.js').success(function(){
numLoaded++;
if (numLoaded == controllers.length) {
return true; //only return after all scripts are loaded, this is blocking, and will fail if all scripts aren't loaded.
}
});
}
}
$routeProvider
.when('/', {
templateUrl: 'views/foo.html',
resolve: {
load: function () {
controllers(['foo'])
}
}
})
.when('/bar',{
templateUrl: 'views/bar.html',
controller: 'BarCtrl',
resolve: {
load: function () {
controllers(['bar','foo']) //you can load multiple controller files
}
}
})
.otherwise({
redirectTo: document.location.pathname
});
}]);
/views/foo.html
<section ng-controller='FooCtrl'>
{{text}}
</section>
/views/bar.html
<section ng-controller='BarCtrl'>
{{text2}}
</section>
<section ng-controller='FooCtrl'>
{{text}}
</section>
/controllers/bar.js
app.registerCtrl('BarCtrl',function($scope){
$scope.text2 = 'Test';
});
You can have pure AngularJS lazy loading.
Create "LazyService":
var ng = angular.module('app');
ng.factory('lazyService', [ '$http', function($http) {
var jsPath = 'js/${ name }.js';
var promisesCache = {};
return {
loadScript: function(name) {
var path = jsPath.replace('${ name }', name);
var promise = promisesCache[name];
if (!promise) {
promise = $http.get(path);
promisesCache[name] = promise;
return promise.then(function(result) {
eval(result.data);
console.info('Loaded: ' + path);
});
}
return promise;
}
}
}]);
Then, define your config:
var ng = angular.module('app', [ 'ngRoute' ]);
ng.config([ '$routeProvider', '$controllerProvider', '$provide', function($routeProvider, $controllerProvider, $provide) {
// Lazy loading
ng.lazy = {
controller: $controllerProvider.register,
//directive: $compileProvider.directive,
//filter: $filterProvider.register,
factory: $provide.factory,
service: $provide.service
}
$routeProvider
.when('/', {
templateUrl: 'view/home.html'
})
.when('/vendor', {
templateUrl: 'view/vendor.html',
resolve: {
svc: [ 'lazyService', function(lazyService) {
return lazyService.loadScript('services/vendor');
}],
ctrl: [ 'lazyService', function(lazyService) {
return lazyService.loadScript('controllers/vendor');
}]
}
});
. . .
On "js/services/vendor.js", create service as:
var ng = angular.module('app');
ng.lazy.service('vendorService', [ function() {
. . .
On "js/controllers/vendor.js", create controller as:
var ng = angular.module('app');
ng.lazy.controller('vendorController', [ function() {
. . .
The "resolve" property on when defines which promises should be resolved before route loads.
The best way to do what you are asking is to instead use a directive and tie the controller and template together that way so its bound at the appropriate time. Currently, the binding it not happening in lazy.htm at the right time unless you declare a global function as you've shown in your second example.
Ideally - Angular will force you to separate HTML and JS as in newer versions this may be enforced more often.
You may have to use requireJS
http://solutionoptimist.com/2013/09/30/requirejs-angularjs-dependency-injection/
For the sake of trick can you try
ng-controller-controller="'lazy'"
or
In HTML
ng-controller-controller="myObject.controller"
Somewhere inject
$scope.myObject.controller = $controller('lazy', {$scope: $scope})
Try this ARI plugin for Angular JS. It helps you to lazy load the controller scripts on demand.
You also can use Directives to load your controller!
A example here:
https://gist.github.com/raphaelluchini/53d08ed1331e47aa6a87
I am sending you sample code. It is working fine for me. So please check this:
var myapp = angular.module('myapp', ['ngRoute']);
/* Module Creation */
var app = angular.module('app', ['ngRoute']);
app.config(['$routeProvider', '$controllerProvider', function ($routeProvider, $controllerProvider) {
app.register = {
controller: $controllerProvider.register,
//directive: $compileProvider.directive,
//filter: $filterProvider.register,
//factory: $provide.factory,
//service: $provide.service
};
// so I keep a reference from when I ran my module config
function registerController(moduleName, controllerName) {
// Here I cannot get the controller function directly so I
// need to loop through the module's _invokeQueue to get it
var queue = angular.module(moduleName)._invokeQueue;
for (var i = 0; i < queue.length; i++) {
var call = queue[i];
if (call[0] == "$controllerProvider" &&
call[1] == "register" &&
call[2][0] == controllerName) {
app.register.controller(controllerName, call[2][1]);
}
}
}
var tt = {
loadScript:
function (path) {
var result = $.Deferred(),
script = document.createElement("script");
script.async = "async";
script.type = "text/javascript";
script.src = path;
script.onload = script.onreadystatechange = function (_, isAbort) {
if (!script.readyState || /loaded|complete/.test(script.readyState)) {
if (isAbort)
result.reject();
else {
result.resolve();
}
}
};
script.onerror = function () { result.reject(); };
document.querySelector(".shubham").appendChild(script);
return result.promise();
}
}
function stripScripts(s) {
var div = document.querySelector(".shubham");
div.innerHTML = s;
var scripts = div.getElementsByTagName('script');
var i = scripts.length;
while (i--) {
scripts[i].parentNode.removeChild(scripts[i]);
}
return div.innerHTML;
}
function loader(arrayName) {
return {
load: function ($q) {
stripScripts(''); // This Function Remove javascript from Local
var deferred = $q.defer(),
map = arrayName.map(function (obj) {
return tt.loadScript(obj.path)
.then(function () {
registerController(obj.module, obj.controller);
})
});
$q.all(map).then(function (r) {
deferred.resolve();
});
return deferred.promise;
}
};
};
$routeProvider
.when('/first', {
templateUrl: '/Views/foo.html',
resolve: loader([{ controller: 'FirstController', path: '/MyScripts/FirstController.js', module: 'app' },
{ controller: 'SecondController', path: '/MyScripts/SecondController.js', module: 'app' }])
})
.when('/second', {
templateUrl: '/Views/bar.html',
resolve: loader([{ controller: 'SecondController', path: '/MyScripts/SecondController.js', module: 'app' },
{ controller: 'A', path: '/MyScripts/anotherModuleController.js', module: 'myapp' }])
})
.otherwise({
redirectTo: document.location.pathname
});
}])
And in HTML Page:
<body ng-app="app">
<div class="container example">
<!--ng-controller="testController"-->
<h3>Hello</h3>
<table>
<tr>
<td>First Page </td>
<td>Second Page</td>
</tr>
</table>
<div id="ng-view" class="wrapper_inside" ng-view>
</div>
<div class="shubham">
</div>
</div>
Thank U

Categories