I'm working with a Play framwork project using angular-seed project as a basis. It creates an array of controllers and passes them into the angularjs instance I guess, somewhat different to other tutorials I've seen. When I try to link a div to the controller the controller function isn't found:
angular.js:13920 Error: [ng:areq] Argument 'menuCtrl' is not a function, got undefined
Here's how I link in the controller:
<div id="wrapper" class="row row-offcanvas row-offcanvas-left" ng-controller="menuCtrl" uib-collapse="showMenu" horizontal>
<div id="sidebar-wrapper" class="col-xs-6 col-sm-3 sidebar-offcanvas" ng-show="menuOpen" role="navigation">
<ul class="nav nav-pills nav-stacked">
<li>view1</li>
<li>view2</li>
</ul>
</div>
<div id="page-content-wrapper" class="col-xs-12 col-sm-9">
<div ng-view></div>
<div>Angular seed app: v<span app-version></span></div>
</div>
</div>
Here's the main.js:
/*global require, requirejs */
'use strict';
requirejs.config({
paths: {
'angular': ['../lib/angularjs/angular'],
'angular-route': ['../lib/angularjs/angular-route'],
'ui-bootstrap':['../lib/angular-ui-bootstrap/ui-bootstrap']
},
shim: {
'angular': {
exports : 'angular'
},
'angular-route': {
deps: ['angular'],
exports : 'angular'
},
'ui-bootstrap': {
deps: ['angular'],
exports: 'ui-bootstrap'
}
}
});
require(['angular', './controllers', './directives', './filters', './services', 'angular-route', "ui-bootstrap"],
function(angular, controllers) {
// Declare app level module which depends on filters, and services
angular.module('eprogram2', ['eprogram2.filters', 'eprogram2.services', 'eprogram2.directives', 'ngRoute']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/view1', {templateUrl: 'partials/partial1.html', controller: controllers.MyCtrl1});
$routeProvider.when('/view2', {templateUrl: 'partials/partial2.html', controller: controllers.MyCtrl2});
$routeProvider.otherwise({redirectTo: '/view1'});
}]);
angular.module('eprogram2', ['ui.bootstrap']);
angular.bootstrap(document, ['eprogram2']);
});
and the controller.js:
'use strict';
define(function() {
/* Controllers */
var controllers = {};
controllers.MyCtrl1 = function() {}
controllers.MyCtrl1.$inject = [];
controllers.MyCtrl2 = function() {}
controllers.MyCtrl2.$inject = [];
controllers.menuCtrl = function($scope, $window) {
$scope.menuOpen = false;
console.log("MenuCtrl");
// Detect if mobile portrait screen size
$scope.is_mobile = ($window.innerWidth <= 480);
if ($scope.isMobile) {
$scope.menuOpen = false;
console.log("mobile detected - close menu")
} else {
$scope.menuOpen = true;
console.log("not mobile - open menu")
}
}
controllers.menuCtrl.$inject = ['$scope', '$window'];
return controllers;
});
I've tried using the template project's controllers and mine but no go. The routing instructions find their controllers no problem in main.js, but the controllers don't seem to be exposed to the HTML page. I've tried:
eprogram2.controllers.menuCtrl
controllers.menuCtrl
eprogram2.menuCtrl
formats as well, but all return the same not a function, got undefined message. Any suggestions about what my boneheaded mistake is?
You have 2 declarations for module('eprogram2') .
You can only declare a module once.
Remove:
angular.module('eprogram2', ['ui.bootstrap']);
and add 'ui.bootstrap' dependency to the initial declaration.
On a side note it looks like the seed you are using is fairly old. I would suggest following John Papa's style guide and the rule of 1 and have one component per file. You will appreciate it in the long run.
The idea of grouping controllers into controller modules and directives into directive modules has long been superseded with grouping features into modules. They become a lot more portable that way
Related
I'm just getting started with AngularJs. And I'm trying to implement a login directive. But I don't see the output? I've no errors in my console.
My application structure:
(index.html is not visible)
login.directive.js :
(function() {
'use strict';
angular
.module('lnjapp.login',[])
.directive('login', login);
function login() {
var directive = {
template: '<p>test</p>',
//restrict: 'E',
Controller: LoginController,
controllerAs: 'vm'
};
return directive;
}
})();
app.js :
(function () {
'use strict';
angular.module('lnjapp', ['ngRoute', 'ngCookies', 'angular.filter','lnjapp.login','lnjapp.config'])
.constant('GLOBALS', {
url:'http://domain.dev/api/v1/'
});
$(document).ready(function() {
$.material.init();
});
})();
app/pages/login.html:
<login></login>
--EDIT--
login.controller.js:
(function() {
'use strict';
angular.module('lnjapp.login',[])
.controller('LoginController', LoginController);
function LoginController()
{}
})();
route-config.js:
angular
.module('lnjapp.config',[])
.config(config);
function config($routeProvider) {
$routeProvider
.when('/', {
templateUrl: '/app/pages/login.html'
});
}
What am I doing wrong here?
You are creating your lnjapp.login twice, once in login.directive.js and again in login.controller.js. The second time the module is created, it overwrites the first, and whatever was created in the first file will no longer be accessible.
You should always only create a module once, and get the already created module to add additional features in all other cases.
Set (create): angular.module('lnjapp.login',[])
Get (consume): angular.module('lnjapp.login')
For more info and other best practices, see John Papa's excellent Angular Style Guide.
I'm working on making a collapsible menu with Angular, but it seems to have broken the rest of my webpage! I've isolated it to be somewhere in my app.js file, which controls everything. I get the error stated in the title:
Error: [ng:areq] Argument 'SidebarController' is not a function, got undefined.
'use strict';
(function() {
// Declare app level module which depends on views and components
angular.module('app', [
'ngRoute',
'app.view1',
'app.view2',
'app.version'
]).
config(['$routeProvider', function($routeProvider) {
$routeProvider.otherwise({redirectTo: '/view1'});
}]);
//Sidebar toggle
app.controller('SidebarController', function($scope) {
$scope.state = false;
$scope.toggleState = function() {
$scope.state = !$scope.state;
};
});
app.directive('sidebarDirective', function() {
return {
link : function(scope, element, attr) {
scope.$watch(attr.sidebarDirective, function(newVal) {
if(newVal)
{
element.addClass('show');
return;
}
element.removeClass('show');
});
}
};
});
}())
And here's the relevant <div> that contains the sidebar:
<div id="page-wrapper" ng-class="" ng-cloak>
<div id="sidebar-wrapper" ng-controller="SidebarController" class="sidebar" sidebar-directive="state">
<a id="navigation-toggle" ng-click="toggleState()">MENU</a>
<ul class="navigation">
<li class="navigation-items">
Denon Settings
</li>
<li class="navigation-items">
Light Settings
</li>
</ul>
</div>
What's going on?
I got it! The problem was that I did not properly define app. The declaration should read:
// Declare app level module which depends on views and components
var app = angular.module('app', [
'ngRoute',
'app.view1',
'app.view2',
'app.version'
]).
config(['$routeProvider', function($routeProvider) {
$routeProvider.otherwise({redirectTo: '/view1'});
}]);
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
}]);
});
I am trying to create a seed application using Angular JS,RequireJS & Framework 7. I have so far created the following folder structure.
My main folder looks like below:
and my scripts folder looks like this :
and my libraries are :
I was able to the view -> controller flow working properly. But when I try to inject a service object to the controller I get the following error.
I am sure I must be missing something. I have given my code below:
require-main:
(function() {
require.config({
baseUrl: "scripts",
// alias libraries paths
paths: {
'angular': '../libs/angular',
'angular-route': '../libs/angular-route',
'angular-animate':'../libs/angular-animate',
'angularAMD': '../libs/angularAMD.min',
'Framework7':'../libs/framework7',
'UserController':'controller/UserCtrl',
'WebCallManager':'services/WebCallManager'
},
// Add angular modules that does not support AMD out of the box, put it in a shim
shim: {
'angularAMD': ['angular'],
'angular-route': ['angular'],
'angular-animate':['angular'],
'Framework7':{exports: 'Framework7'}
},
//kick start application
deps: ['app']
});
require(['Framework7'], function(Framework7) {
f7 = new Framework7({
modalTitle: 'Seed App',
swipePanel: 'left',
animateNavBackIcon: true
});
return {
f7: f7
};
});
})();
app.js :
define(['angularAMD', 'angular-route','angular-animate'], function (angularAMD) {
var app = angular.module("app", ['ngRoute','ngAnimate']);
app.config(function ($routeProvider) {
$routeProvider.when("/", angularAMD.route({ templateUrl: '../pages/login.html',controller: 'UserController'}));
$routeProvider.when("/login", angularAMD.route({ templateUrl: '../pages/home.html', controller: 'UserController'}));
});
angularAMD.bootstrap(app);
return app;
});
UserController :
define(['app'], function (app) {
app.register.controller('UserController', function ($scope,$location,webcallService) {
$scope.loginUser = function(){
console.log("Login User Called...");
$location.path('/login').replace();
console.log("View Navigated...");
};
$scope.slidePanel = function(){
f7.openPanel('left');
};
$scope.doWebCall = function(){
console.log("Doing the Web Call...");
webcallService.sendGetRequest();
};
});
});
WebCallManager.js (Service)
define(['app'], function (app) {
app.service('webcallService', function() {
var self = this;
self.sendGetRequest = function() {
console.log("Sending HTTP Get Request");
}
self.sendPostRequest = function() {
console.log("Sending HTTP Post Request");
}
});
});
And my pages :
index.html:
<!DOCTYPE html>
<html>
<head>
<script data-main="scripts/main" src="libs/require.js"></script>
</head>
<body>
<div>
<div class="slide-animation page-content" ng-view ></div>
</div>
</body>
</html>
login.html:
<div class="content-block login-input-content">
<div class="store-data list-block">
<div>
<input type="text" class="login-name" placeholder="Username">
</div>
<div>
<input type="password" class="password" placeholder="Password">
</div>
<a class="multi-language" href="#"><i class="icon ios7-world-outline"></i><span>english</span></a>
</div>
</div>
<div class="content-block login-btn-content">
<button ng-click="loginUser()" class="button button-big button-submit login-submit">Login</button>
</div>
Home.html:
<div>
<h3>Welcome to Mobility In Angular-JS</h3>
<div class="content-block login-btn-content">
<button ng-click="doWebCall()" class="button button-big button-submit login-submit">Send Get</button>
<br/><br/>
<button ng-click="doWebCall()" class="button button-big button-submit login-submit">Send Post</button>
</div>
Could Anyone help me out ??. YOu can also download and run the entire project here.
You are registering the service as webcallService:
app.service('webcallService', function() {
But inject the $webcallService in the controller:
app.register.controller('UserController', function ($scope, $location, $webcallService) {
Choose one, the one without $ is recommend though, so declare your controller with webcallService:
app.register.controller('UserController', function ($scope, $location, webcallService) {
EDIT: Found one more problem, after reading the angularAMD documentation, it seems you have to add the requirejs module WebCallManager that contain the webcallService angularjs service as a dependency in define() as well.
Therefore, it should be like this:
define(['app', 'WebCallManager'], function (app) {
app.register.controller('UserController', function ($scope,$location,webcallService) {
Otherwise, the module WebCallManager will not be loaded on-demand.
EDIT: Found the third problem, you register the controller via app.register, but register the service directly via app.. You need to be consistent here, but the app.register has been deprecated (See this thread).
Therefore the best would be removing the app.register like this:
app.controller('UserController', ..
And in app.js change from:
angularAMD.bootstrap(app);
return app;
to
return angularAMD.bootstrap(app);
Hope this helps.
I am trying to add custom page CSS/JS to my partials via controllers, i have created a custom directive for it but when i am loading the CSS using it it gets unnecessary parameters which i don't want, and when i load JS using it my JS does not load the the right time(meaning the init functions written in the page gets called before, leaving the error)
DIRECTIVE
app.directive('head', ['$rootScope','$compile',
function($rootScope, $compile){
return {
restrict: 'E',
link: function(scope, elem){
var html = '<link rel="stylesheet" ng-repeat="(routeCtrl, cssUrl) in routeStyles" ng-href="{{cssUrl}}" />';
elem.append($compile(html)(scope));
scope.routeStyles = {};
$rootScope.$on('$routeChangeStart', function (e, next, current) {
if(current && current.$$route && current.$$route.css){
if(!Array.isArray(current.$$route.css)){
current.$$route.css = [current.$$route.css];
}
angular.forEach(current.$$route.css, function(sheet){
delete scope.routeStyles[sheet];
});
}
if(next && next.$$route && next.$$route.css){
if(!Array.isArray(next.$$route.css)){
next.$$route.css = [next.$$route.css];
}
angular.forEach(next.$$route.css, function(sheet){
scope.routeStyles[sheet] = sheet;
});
}
});
}
};
}
]);
APP CONTROLLER
app.config(['$routeProvider', function($routeProvider){
$routeProvider
.when('/some/route/1', {
templateUrl: 'partials/partial1.html',
controller: 'Partial1Ctrl',
css: 'css/partial1.css'
})
.when('/some/route/2', {
templateUrl: 'partials/partial2.html',
controller: 'Partial2Ctrl',
css: ['css/partial2_1.css','css/partial2_2.css']
})
}]);
Output I am getting
CSS
<link rel="stylesheet" ng-repeat="(routeCtrl, cssUrl) in routeStyles" ng-href="css/createtroll.css" class="ng-scope" href="css/partial2.css">
HTML
<script ng-repeat="(routeCtrl, scriptUrl) in routeScript" ng-src="js/page.css" class="ng-scope" src="css/scroll.js"></script>
I want know how to remove the ng-directives form the output and how to load js before document.ready so that I don't get the error. Any help is much appreciated.
it seems that you are looking for a way to lazy-load some aspect of our AngularJS application by loading JS and CSS files asynchronously.
You cannot use controllers/directives for loading your files because your app has already been bootstrapped.
You'll need some kind of file/module loader, for example you can use RequireJS - a JavaScript file and module loader.
there are already a lot of examples and implementation of RequireJS and AngularJS.
Example:
require.config({
baseUrl: "js",
paths: {
'angular': '.../angular.min',
'angular-route': '.../angular-route.min',
'angularAMD': '.../angularAMD.min'
},
shim: { 'angularAMD': ['angular'], 'angular-route': ['angular'] },
deps: ['app']
});
Reference:
http://marcoslin.github.io/angularAMD/#/home
http://www.startersquad.com/blog/angularjs-requirejs/
http://www.bennadel.com/blog/2554-Loading-AngularJS-Components-With-RequireJS-After-Application-Bootstrap.htm
http://requirejs.org/