I am building a large angular app comprised of various modules
- app
-- member
--- newMember
--- memberDashboard
-- linguistics
-- etc
--- etc etc
In the html I am instantiating individual modules, because I believe there to be a performance improvement over bootstrapping the entire app.
<div ng-app="linguistics">
<div ui-view autoscroll="true"></div>
</div>
However, this means that I have to repeat myself in module configuration. i.e.:
angular.module('linguistics', [
'ui.router',
'ui.bootstrap',
'googlechart',
'babelServices',
'babelFilters'
]).config(function($stateProvider, $urlRouterProvider, $locationProvider, $httpProvider) {
$locationProvider.html5Mode(true);
}).config(function($provide) {
return $provide.decorator('$uiViewScroll', function($delegate, $window) {
return function(uiViewElement) {
//eventually do something more intelligent with the uiViewElement
return $window.scrollTo(0, 0);
};
});
});
html5Mode, scrollTo etc will be repeated across modules. Is there a better way to do this?
I'd add a configuration module, that will handle the grunt work of setting up html5Mode, scrollTo etc.
angular.module('configuration', ['ui.router'])
.config(function ($locationProvider, $provide) {
$locationProvider.html5Mode(true);
// For angular 1.3
$locationProvider.html5Mode({
enabled: true,
requireBase: /* true/false */
});
$provide.decorator('$uiViewScroll', function ($delegate, $window) {
return function (uiViewElement) {
return $window.scrollTo(0, 0);
}
});
});
And then in your subsequent modules:
angular.module('linguistics', ['configuration']);
Related
I'm using ocLazyLoad and I have some external angular libraries (Like Chart.js and pascalprecht.translate) and I need to lazy load them in some routes, as you know, for the common angular module dependency injection should be like:
var angularApp = angular.module('myApp',
['oc.lazyLoad', 'pascalprecht.translate', 'chart.js']);
Now, I just need to lazy loading pascalprecht.translate in one of my controllers and also lazy loading chart.js, in another controller, but I still need to add inject them to myApp module but I don't know how to inject and I do not use $stateProvider
I tried this my controller that I needed chart.js:
//Load here.
//$ocLazyLoad.load('./panel/dist/test.js');
angular.module('myApp', ['chart.js', [
'./panel/dist/static/chart.min.js',
'./panel/dist/static/angular-chart.min.js'
]]);
$ocLazyLoad.load('./panel/dist/static/chart.min.js');
$ocLazyLoad.load('./panel/dist/static/angular-chart.min.js');
But I got this error:
angular-chart.min.js:10Uncaught Error: Chart.js library needs to
included, see http://jtblin.github.io/angular-chart.js/
First, you do not need to inject chart.js in your dependency injection, this should be your module:
var angularApp = angular.module('myApp', [ 'oc.lazyLoad' ]);
Now, you want to have access to some libraries from different controllers (let's say routes), as you said you do not use $stateProvider which means you do not use ui-router (which is a third-party library to work with routes and URLs).
This is my suggestion (just a simple solution):
angularApp.config(function ($routeProvider, $locationProvider) {
$routeProvider.when('/home', {
templateUrl: 'views/home.html',
controller: 'HomeController',
resolve: {
store: function ($ocLazyLoad) {
return $ocLazyLoad.load(
{
serie: true,
name: "chart.js",
files: [
"./static/chart.min.js",
"./static/chart-angular.min.js",
]
}
);
}
}
});
$routeProvider.when('/needs-translate', {
templateUrl: 'views/needs-translate.html',
controller: 'translateController',
resolve: {
store: function ($ocLazyLoad) {
return $ocLazyLoad.load(
{
serie: true,
name: "pascalprecht.translate",
files: [
"./static/translate.js"
]
}
);
}
}
});
$routeProvider.otherwise({
redirectTo: '/home'
});
// use the HTML5 History API
$locationProvider.hashPrefix = '!';
$locationProvider.html5Mode(true);
});
By the way, if you are using ui.router, this Github issue would be useful for you
I installed AngularJs with MVC4 using Nuget package and created a bundle for AngularJS
bundles.Add(new Bundle("~/bundles/scripts")
.Include("~/Scripts/angular.js")
.Include("~/Scripts/jquery-{version}.js"));
In Layout I included it as follow:
#Scripts.Render("/scripts/angular-route.js")
#Scripts.Render("/scripts/loginController.js")
#Scripts.Render("/scripts/routeConfig.js")
routeConfig.js
angular
.module('MyApp', [
'ngRoute',
'MyApp.ctrl.crud',
])
.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
$routeProvider.when('/', {
templateUrl: '/Home/Index',
// controller: 'loginController'
});
$routeProvider.when('/login', {
templateUrl: '/Home/loginPage',
controller: 'crudController'
});
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
}]);
loginController.js
angular
.module('MyApp.ctrl.crud', [])
.controller('loginController', [
'$scope',
function ($scope) {
alert("In Login Controller")
}
]);
When I program is display following exception:
WARNING: Tried to load angular more than once.
Why I get this Warning?
I struggling with understanding why I'm seeing several "No define call for" when attempting to load my angular application. Well I know they are there because I'm using enforeDefine: true, but what is wrong with my code? What do I need to do to satisfy the enforceDefine?
Errors:
main.js
/*global require, requirejs */
'use strict';
requirejs.config({
enforceDefine: true,
paths: {
angular: ['//cdn.jsdelivr.net/webjars/org.webjars/angularjs/1.4.0/angular.min','../lib/angularjs/angular.min'],
'angular-messages': ['//cdn.jsdelivr.net/webjars/org.webjars/angularjs/1.4.0/angular-messages.min','../lib/angularjs/angular-messages.min'],
'angular-resource': ['//cdn.jsdelivr.net/webjars/org.webjars/angularjs/1.4.0/angular-resource.min','../lib/angularjs/angular-resource.min'],
'angular-ui-bootstrap': ['//cdn.jsdelivr.net/webjars/org.webjars/angular-ui-bootstrap/0.13.0/ui-bootstrap-tpls.min','../lib/angular-ui-bootstrap/ui-bootstrap-tpls.min'],
uiRouter: ['//cdn.jsdelivr.net/webjars/org.webjars/angular-ui-router/0.2.15/angular-ui-router.min','../lib/angular-ui-router/angular-ui-router.min'],
bootstrap: ['//cdn.jsdelivr.net/webjars/org.webjars/bootstrap/3.3.4/bootstrap.min','../lib/bootstrap/js/bootstrap.min'],
jquery: ['//cdn.jsdelivr.net/webjars/org.webjars/jquery/2.1.4/jquery.min','../lib/jquery/jquery.min'],
async: '../lib/requirejs-plugins/src/async'
},
shim: {
angular: {
exports : 'angular'
},
uiRouter: {
deps: ['angular']
},
'angular-ui-bootstrap': {
deps: ['angular']
},
'angular-resource': {
deps: ['angular']
},
'angular-messages': {
deps: ['angular']
},
bootstrap: {
deps: ['jquery'],
exports: 'jQuery.fn.popover'
}
},
deps: ['app']
});
app.js
/*global require, requirejs */
'use strict';
define(['angular',
'./controllers',
'./directives',
'./filters',
'./services',
'bootstrap',
'jquery',
'uiRouter',
'angular-ui-bootstrap',
'angular-messages',
'angular-resource',
'async',
'./gmaps'
],
function(angular, controllers) {
// Declare app level module which depends on filters, and services
angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives', 'ui.router', 'ngMessages','ngResource','ui.bootstrap']).
config(['$stateProvider','$urlRouterProvider','$httpProvider', function($stateProvider, $urlRouterProvider, $httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
$urlRouterProvider.otherwise('/home');
$stateProvider
// HOME STATES AND NESTED VIEWS ========================================
.state('home', {
url: '/home',
.... several routes here that I hid
});
}]).controller('RouteCtrl', ['$scope','$state', function($scope, $state) {
$scope.$state = $state;
}]);
angular.bootstrap(document, ['myApp']);
});
From this (emphasis mine):
enforceDefine: If set to true, an error will be thrown if a script loads that does not call define() or have a shim exports string value that can be checked.
So the script loaded must either comply with AMD (Angular doesn't) or define an exports in its shim configuration.
Since main is yours, just make it a proper AMD module. The "problem" is that the other scripts (uiRouter, angular-ui-bootstrap, angular-resource, angular-messages) do not actually export anything. My suggestion is just re-export angular (or any other global, e.g. document, but angular seems more relevant) so that you satisfy RequireJS:
requirejs.config({
...
'angular-resource': {
deps: ['angular'],
exports: 'angular'
}, // and so on...
...
});
This is a bypass, but I do not think there is any other way, if you insist on using enforceDefine.
You might need to change the require inside the script you specify as being data-main to be a define instead. There has been a issue on GitHub noted that sounds similar to what you are running into.
The library author suggests that if you use the enforceDefine flag then your data-main module should also use a define.
I have an angular app (with a mix of files ES5 and ES6) that i am developing tests for.
The ES6 files I'm transpiling using babel CLI with these options --modules system --module-ids.
Let's say I have samething like this:
ES5 file:
angular.module('app').controller('A', function($scope) {
...
});
ES6 file:
export class B {
constructor($scope) {
this.$scope = $scope
}
...
}
And I have a file called boot.js:
import {B} from 'controllers/B';
angular.module('app').controller('B', B);
and on my page I import the boot file (using es6-module-loader) and bootstrap the angular app:
System.import('boot').then(function() {
angular.bootstrap(document, ['app']);
});
Now, I assume I need to do something similar to the karma tests - I need to load my boot.js before running my tests.
The way I solve the problem is to call System.impot('boot') in my test files - but doesn't seems to be right:
'use strict';
System.import('boot');
describe('Controller: B', function() {
beforeEach(module('app'));
var $scope;
beforeEach(inject(function(_$rootScope_, $controller) {
scope = _$rootScope_.$new();
$controller('B', {$scope: $scope);
}));
it('...', function() {
});
});
Is there a better way to do this?
The solution I ended up finding involved using karma-systemjs.
Include all your tests files on the systemjs/files section:
systemjs: {
files: [
// TEST FILES
],
configFile: 'system.config.js',
config: {
paths: {
'angular-mocks': 'node_modules/angular-mocks/angular-mocks.js'
}
}
}
And on the tests instead of using:
System.import('boot');
Use:
'use strict';
import 'angular-mocks';
import 'angular/boot.js';
describe('Controller: B', function() {
beforeEach(module('app'));
var $scope;
beforeEach(inject(function(_$rootScope_, $controller) {
scope = _$rootScope_.$new();
$controller('B', {$scope: $scope);
}));
it('...', function() {
});
});
Hopefully this will help someone else in the future.
I am using angular to provide the link for my page.
I have something like
//main app configuration
app.js
'use strict';
angular.module('myApp', [
'ngRoute',
'myApp.filters',
'myApp.services',
'myApp.directives'
]).
config(['$routeProvider', function($routeProvider) {
}]);
//test page configuration
test-controller.js
angular.module('myApp', []).
config(function ($routeProvider) {
$routeProvider.
when('/test/:link', {
templateUrl: 'test/:link.html',
constroller: 'Ctrl'
}).
when('/test2/:link', {
templateUrl: 'test2/:link.html',
constroller: 'Ctrl'
})
}).
controller('Ctrl', ['$scope', function ($scope) {
//scope data
}])
for some reason, the $routeprovide in my test-controller.js doesn't work and output module injection error.
Can anyone help me about it? Thanks a lot!
At first glance, it is because you didn't add 'ngRoute' as dependency in the second definition