Does angularJS have anything in place to lazyload external JS/CSS files based on ng-controller namespaces? So that the following would append com.myApp.SomeClass.js and com.myApp.SomeClass.css to the document head?
<div ng-controller="com.myApp.SomeClass"></div>
Not yet, but it is in the works post v1.0.
Is your app so big that you need it? We have some impressively big apps, and have not run into this need yet, since the controllers are much more dense then when writing the same behavior without angular.
how about using slowscript? It's really easy to lazyload on angularjs
Example:
https://github.com/flrngel/slowscript-angular-require-lazyload
Slowscript:
https://github.com/flrngel/slowscript
core code from website
app.js
app = angular.module("mainApp", ["ui.router"]).run(function($rootScope){
$rootScope.$on('$viewContentLoaded',function(){
slowscript.execute();
});
});
app.config(function($stateProvider, $urlRouterProvider) {
$stateProvider.state("sexy", {
url: "/sexy",
views: {
"contents": {
templateUrl: "/views/test.html",
controller: "Sexy",
reloadOnSearch: true
}
}
});
});
app.controller("Sexy", function($scope) {
slowscript.queue(function(){
slowscript.$global.sexy($scope);
});
});
test.html (angular view template)
<div ng-controller="Sexy">
<input list="univ">
<datalist id="univ">
<option ng-repeat="univ in univs" value="{{univ.name}}"></option>
</datalist>
</input>
<input type="submit"></input>
<noscript src="test.js" type="text/slowscript"></noscript>
</div>
test.js
require(['angular','slowscript'],function(angular,slowscript){
slowscript.$global.sexy=(function($scope){
console.log("tada~");
$scope.univs = [{"idx": 1,"name": "asdf"}, {"idx": 2,"name": "bsdf"}];
$scope.$apply();
});
slowscript.queue_execute();
});
It not possible with stock AngularJS 1.x
However, you can use $oclazyload to defer the loading of code files (js, HTML, CSS)
$ocLazyLoad works perfectly with routers like UI-Router. It returns a promise and uses resolve property to make sure that files are loaded before the view is resolved.
angular.module('myApp', ['ui.router', 'oc.lazyLoad'])
.config(function($stateProvider, $urlRouterProvider, $ocLazyLoadProvider) {
$stateProvider
.state('stateA', {
url: '/stateA',
controller: 'StateACtrl',
templateUrl: 'stateA.html',
resolve: {
load: [ '$ocLazyLoad', function($ocLazyLoad) {
return $ocLazyLoad.load([
{
name: 'stateA',
files: [
'stateA.css',
'stateA.js',
],
},
]);
},
],
},
})
.state('stateB', {
url: '/stateB',
controller: 'StateBCtrl',
templateUrl: 'stateB.html',
resolve: {
load: [ '$ocLazyLoad', function($ocLazyLoad) {
return $ocLazyLoad.load([
{
name: 'stateB',
files: [
'stateB.css',
'stateB.js',
],
},
]);
},
],
},
});
});
I have also created a plunkr to demo a working model.
Documentation to know more about possible config options.
Hope it helps!
Related
I am trying to create my first AngularJS app.
But I can not understand why my routing is not working properly(i think there is some problem in my when() method and directory structure).
Here is my directory structure(I have followed AngularJS standard naming convention).
Directoty Structure
-Home
--sidebar
---sidebar.component
---sidebar.template
--home.component
--home.template
--home.module
-menu
--menu.module
--menu-list
---menu-list.component
---menu-list.template
-app.js
app.js
angular.module('myApp', [
'ngRoute',
'menu',
'home'
]).
config(['$locationProvider', '$routeProvider', function($locationProvider, $routeProvider) {
$locationProvider.hashPrefix('!');
$routeProvider
.when('/menu-list', {
template: '<menu-list></menu-list>'
})
.when('/home', {
template: '<home></home>'
})
.when('/sidebar', {
template: '<sidebar></sidebar>'
})
.otherwise('/home');
}]);
menu.module.js
angular.module('menu',[]);
menu-list.component.js
angular.module('menu')
.component('menu-list', {
templateUrl: 'menu/menu-list/menu-list.html',
controller: [
function MenuListController() {
alert("MenuListController Called");
}
]
});
Been a long time since I've tried using ngRoute but here's how my 'otherwise' statement differs from yours:
.otherwise({
redirectTo: '/home'
});
The difference is here I pass in an object with the property 'redirectTo'. You can check this article out as well.
The Problem was I did not name component correctly. In angularJS to include the view in html we need to name component in camelCase and it will be included by hyphen-case
Component name: 'phoneList'
View name: '<phone-list></phone-list>'
Example from AngularJS-Tutorial
app/index.html:
<html ng-app="phonecatApp">
<head>
...
<script src="bower_components/angular/angular.js"></script>
<script src="app.js"></script>
<script src="phone-list.component.js"></script>
</head>
<body>
<!-- Use a custom component to render a list of phones -->
<phone-list></phone-list>
</body>
</html>
app/phone-list.component.js:
// Register `phoneList` component, along with its associated controller and template
angular.
module('phonecatApp').
component('phoneList', {
template:'phone-list.html',
controller: function PhoneListController() {
//...
}
});
Note:If any error or written badly feel free to Edit
I have two different login views login.html and adminLogin.html so in Angular app.js I added first one as:
$stateProvider
.state('login', {
url: "/login.html",
templateUrl: "../login.html",
controller: "login",
authenticate: false,
resolve: {
deps: ['$ocLazyLoad', function ($ocLazyLoad) {
return $ocLazyLoad.load({
name: 'myapp',
insertBefore: '#ng_load_plugins_before', // load the above css files before a LINK element with this ID. Dynamic CSS files must be loaded between core and theme css files
});
}]
}
})
and it runs correctly, problem is when I try to add second one below this one as:
.state('login', {
url: "/adminLogin.html",
templateUrl: "../adminLogin.html",
controller: "adminLogin",
authenticate: false,
data: { pageTitle: 'INICIAR SESIÓN' },
resolve: {
deps: ['$ocLazyLoad', function ($ocLazyLoad) {
return $ocLazyLoad.load({
name: 'myapp',
insertBefore: '#ng_load_plugins_before', // load the above css files before a LINK element with this ID. Dynamic CSS files must be loaded between core and theme css files
}]
}
})
When I try to acces first one or new one it only show blank page
Note**: if I comment last code, first one runs correctly again.
Some one know what is wrong there? Help is very appreciated. Regards
You have two states with the same name: login. The UI-Router has no idea what to do in that situation. Try re-naming your second state to something like adminLogin.
'use strict';
angular.module('confusionApp', ['ui.router'])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
// route for the home page
.state('app', {
url:'/',
views: {
'header': {
templateUrl : 'views/header.html'
},
'content': {
template : '<h1>To be Completed</h1>',
controller : 'IndexController'
},
'footer': {
templateUrl : 'views/footer.html'
}
}
})
// route for the aboutus page
.state('app.aboutus', {
url:'aboutus',
views: {
'content#': {
template: '<h1>To be Completed</h1>'
}
}
})
// route for the contactus page
.state('app.contactus', {
url:'contactus',
views: {
'content#': {
templateUrl : 'views/contactus.html',
controller : 'ContactController'
}
}
})
// route for the menu page
.state('app.menu', {
url: 'menu',
views: {
'content#': {
templateUrl : 'views/menu.html',
controller : 'MenuController'
}
}
})
// route for the dishdetail page
.state('app.dishdetails', {
url: 'menu/:id',
views: {
'content#': {
templateUrl : 'views/dishdetail.html',
controller : 'DishDetailController'
}
}
});
$urlRouterProvider.otherwise('/');
});
For the app.js file I am trying to use the UI-Router, I used bower to install the the angular dependencies for the UI-Router. They currently have the right path when I include them in the tags. I checked to make sure that the files were also there inside of the bower_components file. Yet when I run the program nothing shows up and the only error that I recieve is the "Uncaught Error: [$injector:modulerr]" error.
It's seem like angular can't find ui-route module,
remember include it in your html. Use something like that
<script src="/bower_components/angular/angular.js"></script>
<script src="/bower_components/angular-ui-router/angular-ui-router.js"></script>
if you are using bower.
Sorry by my english. I hope this will be useful for you.
I had similar issue. What fixed it was to inject '$stateProvider' and '$urlRouterProvider' before using them in the config function such as:
angular.module('confusionApp', ['ui.router'])
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$stateProvider
// .. and so on
}]);
Try load ui.router before you load a script:
<!-- UI-Router -->
<script src="angular-ui-router.js"></script>
<script src="yourscript.js"></script>
I would like to load a file when a specific URL is hit, but I didn't have any success with it yet:
This is how my code looks like:
.state('admin.resources', {
url: '/resources',
templateUrl: 'views/admin/resources.html',
controller: 'ResourceController as res',
resolve: {
loadMyFiles: function ($ocLazyLoad) {
return $ocLazyLoad.load({
name: 'venture',
files: [
'bower_components/angular-ui-tinymce/src/tinymce.js'
]
})
}
}
})
It works all fine if I include it on the index.html like this:
<script type="text/javascript" src="bower_components/angular-ui-tinymce/src/tinymce.js"></script>
I don't want to load id from index.html as I don't want that page to be loaded once the site is loaded. I need that script on a separate page.
Any suggestion?
In order to use the oclazyload, you need to put it in the resolve property:
$stateProvider.state('index', {
url: "/", // root route
views: {
"lazyLoadView": {
controller: 'AppCtrl', // This view will use AppCtrl loaded below in the resolve
templateUrl: 'partials/main.html'
}
},
resolve: { // Any property in resolve should return a promise and is executed before the view is loaded
loadMyCtrl: ['$ocLazyLoad', function($ocLazyLoad) {
// you can lazy load files for an existing module
return $ocLazyLoad.load('js/AppCtrl.js');
}]
}
});
All is explained and well-documented in With your router.
I'm trying to setup a simple angularjs app using ui.router, ocLazyLoad, Foundation and angular-foundation.
The app is a multi-view app with it's components lazy loaded using ocLazyLoad. I have no problem setting up the views and associated controllers. However, I am having an issue when trying to display a Foundation alert. When I try to view my alerts (route1), I get empty alerts. And the stack trace below.
Why is angular applying the alert directive twice? A plunker is available here: http://goo.gl/lhtD0c
Error: [$compile:multidir] Multiple directives [alert, alert] asking for transclusion on:
<div class="alert-box" ng-class="(type || "")" ng-repeat="alert in alerts" type="alert.type" close="closeAlert($index)">
http://errors.angularjs.org/1.2.22/$compile/multidir?p0=alert&p1=alert&p2=t…lerts%22%20type%3D%22alert.type%22%20close%3D%22closeAlert(%24index)%22%3E
at https://code.angularjs.org/1.2.22/angular.js:78:12
at assertNoDuplicate (https://code.angularjs.org/1.2.22/angular.js:6933:15)
at applyDirectivesToNode (https://code.angularjs.org/1.2.22/angular.js:6353:13)
at https://code.angularjs.org/1.2.22/angular.js:6858:37
at https://code.angularjs.org/1.2.22/angular.js:8091:11
at wrappedCallback (https://code.angularjs.org/1.2.22/angular.js:11546:81)
at wrappedCallback (https://code.angularjs.org/1.2.22/angular.js:11546:81)
at https://code.angularjs.org/1.2.22/angular.js:11632:26
at Scope.$eval (https://code.angularjs.org/1.2.22/angular.js:12658:28)
at Scope.$digest (https://code.angularjs.org/1.2.22/angular.js:12470:31)
The body of my index is below:
<body>
<div>
<a class="button" ui-sref="route1">Route 1</a>
<a class="button" ui-sref="route2">Route 2</a>
</div>
<div ui-view></div>
</body>
The javascript associated with this page is:
var myapp = angular.module('myapp', ['ui.router', 'oc.lazyLoad', 'mm.foundation'])
myapp.config(function($stateProvider, $urlRouterProvider){
// For any unmatched url, send to /route2
$urlRouterProvider.otherwise('/route2')
$stateProvider
.state('route1', {
url: "/route1",
controller: 'Route1',
templateUrl: "route1.html",
resolve: {
loadCtrl: ['$ocLazyLoad', function($ocLazyLoad) {
return $ocLazyLoad.load({
name: 'myapp',
files: ['route1.js']
})
}]
}
})
.state('route2', {
url: "/route2",
templateUrl: "route2.html"
})
});
$(function() {
Foundation.global.namespace = '';
$(document).foundation();
})
The problems are associated with route1. Here is the route1 template.
<div ng-controller="Route1">
Route 1 - {{ message }}
<br/>
<alert ng-repeat="alert in alerts"
type="alert.type"
close="closeAlert($index)">{{alert.msg}}</alert>
</div>
and finally the route1.js -
angular.module('myapp').controller('Route1', ['$scope', function($scope) {
$scope.message = 'Hello, world!'
$scope.alerts = [
{ type: 'danger', msg: 'Oh snap! Change a few things up and try submitting again.' },
{ type: 'success round', msg: 'Well done! You successfully read this important alert message.' }
];
}]);
The problem is that it's reloading your "myapp" module dependencies.
Just config ocLazyLoad not to reload foundation like this:
$ocLazyLoadProvider.config({
loadedModules: ['mm.foundation']
});
It will be something like that:
var myapp = angular.module('myapp', ['ui.router', 'oc.lazyLoad', 'mm.foundation'])
myapp.config(function($stateProvider, $urlRouterProvider, $ocLazyLoadProvider){
// For any unmatched url, send to /route2
$urlRouterProvider.otherwise('/route2')
$ocLazyLoadProvider.config({
loadedModules: ['mm.foundation']
});
$stateProvider
.state('route1', {
url: "/route1",
controller: 'Route1',
templateUrl: "route1.html",
resolve: {
loadCtrl: ['$ocLazyLoad', function($ocLazyLoad) {
return $ocLazyLoad.load({
name: 'myapp',
files: ['route1.js']
})
}]
}
})
.state('route2', {
url: "/route2",
templateUrl: "route2.html"
})
});
$(function() {
Foundation.global.namespace = '';
$(document).foundation();
})
Replace this code
<alert ng-repeat="alert in alerts"
type="alert.type"
close="closeAlert($index)">{{alert.msg}}</alert>
by
<div ng-repeat="alert in alerts">
<alert type="alert.type" close="closeAlert($index)">{{alert.msg}}</alert>
</div>
I finally managed to make this work. The problem was that ocLazyLoad was reloading the 'myapp' module. This caused the dependencies to reload. One of the dependencies was mm.foundation which reprocessed all the directives creating a clone of each pair.
To prevent this,I did not tie the second controller to myapp. Instead I created a new app 'route1app'. You can see the updated plunker here: http://goo.gl/lhtD0c