In this plunk I have a sample code running Angular + Angular UI Router + RequireJS. There are two pages, each with a corresponding controller. If you click on View 1, you should see a page that contains a directive.
When the page loads it throws the following exception:
Cannot read property 'controller' of undefined at at my-ctrl-1.js:3
meaning that app is undefined in my-ctrl-1.js even though I'm returning it in app.js. What's wrong with this code?
HTML
<ul class="menu">
<li><a href ui-sref="view1">View 1</a></li>
<li><a href ui-sref="view2">View 2</a></li>
</ul>
<div ui-view></div>
main.js
require.config({
paths: {
'domReady': 'https://cdnjs.cloudflare.com/ajax/libs/require-domReady/2.0.1/domReady',
'angular': 'https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min',
"uiRouter": "https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.2/angular-ui-router"
},
shim: {
'angular': {
exports: 'angular'
},
'uiRouter':{
deps: ['angular']
}
},
deps: [
'start'
]
});
start.js
define([
'require',
'angular',
'app',
'routes'
], function (require, angular) {
'use strict';
require(['domReady!'], function (document) {
angular.bootstrap(document, ['app']);
});
});
app.js
define([
'angular',
'uiRouter',
'my-ctrl-1',
'my-ctrl-2',
'my-dir-1'
], function (angular) {
'use strict';
console.log("app loaded");
return angular.module('app', ['ui.router']);
});
my-ctrl-1.js
define(['app'], function (app) {
'use strict';
app.controller('MyCtrl1', function ($scope) {
$scope.hello = "Hello1: ";
});
});
The problem is that you have a circular dependency between app.js and my-ctrl-1.js. When RequireJS encounters a circular dependency, the references it passes to the modules' factories are going to be undefined. There are many ways to solve the issue. One simple way that would work with the code you show could be to change my-ctrl-1.js to:
define(function () {
'use strict';
return function (app) {
app.controller('MyCtrl1', function ($scope) {
$scope.hello = "Hello1: ";
});
};
});
And in app.js:
define([
'angular',
'my-ctrl-1',
'my-ctrl-2',
'my-dir-1',
'uiRouter',
], function (angular, ctrl1) {
'use strict';
console.log("app loaded");
var app = angular.module('app', ['ui.router']);
ctrl1(app);
return app;
});
Presumably, you'll have to do the same thing with your other controler.
The documentation has a section on the topic of circular dependencies and other methods to handle them.
Related
I'm new to Angular+Require so please bear with me as I couldn't find this information online.
I understand that ng-app is not declared in the html as it's bootstrapped manually, but how is ng-controller used? Or is not used?
In this plunk I have an Angular application that runs under Require, but the $scope fields are not shown, is it because the controller is declared incorrectly?
HTML
This is the name: {{name}}
<br>
This is the toggle: {{singleModel}}
<br>
<button type="button" class="btn btn-primary" ng-model="singleModel"
uib-btn-checkbox btn-checkbox-true="1" btn-checkbox-false="0">
Single Toggle
</button>
<script data-main="main" src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.9/require.min.js"></script>
Javascript - main.js
require.config({
paths: {
angular: 'https://code.angularjs.org/1.2.16/angular',
uiBootstrap : 'https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.4.0/ui-bootstrap-tpls',
app: 'app'
},
shim: {
'angular': {
exports: 'angular'
},
uiBootstrap: {
exports: 'uiBootstrap',
deps: ['angular']
},
'app': ['angular']
}
});
require(['angular', 'app'], function(angular) {
'use strict';
angular.bootstrap(document, ['app']);
});
Javascript - app.js
define([
'angular',
'uiBootstrap'
], function (angular) {
var app = angular.module('app', ['ui.bootstrap']);
app.controller('mainCtrl', function($scope) {
$scope.name = 'World';
$scope.singleModel = 1;
});
});
I have a problem implementing Toaster into my demoApp which uses RequireJS. Here some code:
(function () {
require.config({
paths: {
'angular': 'bower_components/angular/angular',
'jquery': 'bower_components/jquery/dist/jquery',
'toaster': 'bower_components/toaster/toaster'
},
shim: {
angular: {
deps: ['jquery'],
exports: 'angular'
},
toaster: {
deps: ['angular', 'jquery'],
exports: 'toaster'
}
}
});
require([
'angular',
'app',
'toaster',
'jquery'
],
function (angular, app, toaster) {
'use strict';
// toaster is undefined. I add it here just for a check. <<<<<<
angular.bootstrap(angular.element('body')[0], ['myApp']);
});
})();
This is main.js and toaster is undefined where I wrote the comment near the end. The file is loaded as I can see it at the Sources tab in the console.
In addition, wherever I want to use toaster, it is undefined. Here some code from the same demo app:
First case:
define(['somefile', 'toaster'], function (someModule, toaster) {
'use strict';
// toaster is undefined
});
Second case (John Papa Angular Style Guide):
define(['somefile', 'toaster'], function (someModule) {
'use strict';
someModule.controller('NewController', NewController);
NewController.$inject = ['someDeps', 'toaster'];
function NewController(someDeps, toaster) {
// angular.js:13424 Error: [$injector:unpr]
// Unknown provider: toasterProvider <- toaster <- NewController
}
});
Here's what I'm using:
Angular: 1.5.3
RequireJs: 2.2.0
Toaster: 2.0.0
Can anyone tell me what I'm doing wrong?
You have to distinguish between Angular modules and RequireJS modules. Toaster only registers an Angular module, no need to export anything in a RequireJS way.
shim: {
// ...
toaster: {
deps: ["angular", "jquery"]
}
}
Bootstrapping:
require(["angular", "app"], function (angular) {
// here, app.js is loaded in the DOM, so you can bootstrap Angular:
angular.bootstrap(angular.element("body")[0], ["myApp"]);
})
In your app.js:
define(["toaster" /* , ... */], function () {
// here, toaster.js is loaded in the DOM, so you can add the "toaster" Angular module in your Angular app dependencies:
return angular.module("myApp", ["toaster" /* , ... */]);
});
Anywhere else:
define(["app"], function (app) {
// as myApp depends on toaster, you can inject the toaster service the Angular way:
app.controller("MyController", ["toaster", function (toaster) {
// ...
}]);
});
I have following setup for my project. Everything works fine.
In my Index.html I have two links (two $state). If I click on one of them, appropriate controller gets initiated dynamically as required. So dynamic concept works fine. But look at my index.html page below,
Index.html
<script src="~/Scripts/require.js" data-main="ANGULAR/main.js"></script>
<div data-ng-controller="appCtrl"> // only this line is not working and throwing an error saying appCtrl is not a function...
// Everything works fine. There is no problem at all. But look at the above line (data-ng-controller="appCtrl"). I know how can I initiate controller dynamically this way?
// When this line gets initiated it throws an error stating that appCtrl is not a function. I really don't know how to initiate appCtrl with this following setup.
<a ui-sref="dashboard">DASHBOARD</a><br /> //works fine
<a ui-sref="login">LOGIN</a> //works fine
<ui-view></ui-view> //works fine
</div>
main.js
require.config({
paths: {
"angular": "//localhost:59293/Scripts/angular",
"ui-router": "//localhost:59293/Scripts/angular-ui-router",
"ui-bootstrap": "//localhost:59293/Scripts/angular-ui/ui-bootstrap-tpls",
// "appCtrl":"//localhost:59293/ANGULAR/APP/appCtrl"
},
shim: {
"angular": {
exports: 'angular'
},
"ui-router": {
deps: ['angular']
},
"ui-bootstrap": {
deps: ['angular']
},
// "appCtrl": {
// deps: ['angular']
// }
}
});
define(
['angular',
'APP/app',
'APP/appCtrl' // Should I write this here ????????????????
], function (angluar, app) {
angular.bootstrap(document, ['MyApp'])
});
app.js looks like this,
define([
'angular',
'ui-router',
'ui-bootstrap',
], function (angular) {
var app = angular.module('MyApp', ['ui.router', 'ui.bootstrap']);
function lazy() {
var self = this;
this.resolve = function (controller) {
return {
ctrl: ['$q', function ($q) {
var defer = $q.defer();
require(['controllers/' + controller], function (ctrl) {
app.register.controller(controller, ctrl);
defer.resolve();
});
return defer.promise;
}]
};
};
this.$get = function () {
return self;
};
}
function config($stateProvider, $urlRouterProvider,
$controllerProvider, $compileProvider,
$filterProvider, $provide, lazyProvider) {
$urlRouterProvider.otherwise('/dashboard');
$stateProvider
.state("dashboard", {
url: "/dashboard",
controller: 'Dashboard/dashboardCtrl', // this works fine
controllerAs: 'vm',
templateUrl: 'ANGULAR/TEMPLATES/DASHBOARD/dashboard.html',
resolve: lazyProvider.resolve('Dashboard/dashboardCtrl')
})
.state("login", {
url: "/login",
controller: 'loginCtrl', //this works fine
controllerAs: 'vm',
templateUrl: 'ANGULAR/TEMPLATES/Login.html',
resolve: lazyProvider.resolve('loginCtrl')
})
;
app.register = {
controller: $controllerProvider.register,
directive: $compileProvider.directive,
filter: $filterProvider.register,
factory: $provide.factory,
service: $provide.service,
constant: $provide.constant
};
}
app.provider('lazy', lazy);
app.config(config);
return app;
});
appCtrl.js // I want this to work correctly.
//This controller doesn't get called with data-ng-controller attribute :(
// how and where should I add appCtrl.js reference as it is not defined in route config function? in main.js? if Yes, then how?
// I have commented code in main.js. please help and suggest.
define([
], function () {
console.log('appCtrl controller loaded');
ctrl.$inject = ['$http','$scope'];
function ctrl($http,$scope) {
this.message = '-- from a lazy controller.';
debugger;
$scope.myVar= "hello world"; // I want this value in HTML page.
};
return ctrl;
});
Please look at http://plnkr.co/edit/UDqaD7QKvgqtzgttXLHq?p=preview
but this is not working as mentioned... I just want to initiate appCtrl.js with ng-controller attribute dyanmically.
First, I've never seen a controller written like that. So that might be one of your problems. Another problem I see is that you are not declaring your controllers. Here's a plunker http://plnkr.co/edit/f343W3?p=preview
But here's the code. First, in your app.js
var app = angular.module('MyApp', [
'ui.router',
// Add your controller
'MyApp.controllers.appCtrl'
]);
Otherwise it angular won't know what you mean.
Second, your controller:
(function (){
'use strict';
function appCtrl(){
var vm = this;
vm.appVar = "Hi from appCtrl";
}
angular.module('MyApp.controllers.appCtrl', [])
.controller('appCtrl', appCtrl);
})();
Done like that, and angular should have no troubles finding your controllers.
I am trying to load a controller so that my view will display. Actually I write my controller .Route or config also .But I am not able to load my controller and route file how to load controller using require.js so that my login.html page is display?
Here is my Plunker:
http://plnkr.co/edit/DlI7CikKCL1cW5XGepGF?p=preview
main.js
requirejs.config({
paths: {
ionic:'http://code.ionicframework.com/1.0.0-beta.1/js/ionic.bundle.min',
},
shim: {
ionic : {exports : 'ionic'}
}
});
route.js
/*global define, require */
define(['app'], function (app) {
'use strict';
app.config(['$stateProvider', '$urlRouterProvider',
function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('login', {
url: "/login",
templateUrl: "login.html",
controller: 'LoginCtrl'
})
$urlRouterProvider.otherwise("/login");
}]);
});
Any guess how to load view?
You just need to do:
main.js
requirejs.config({
paths: {
ionic:'http://code.ionicframework.com/1.0.0-beta.1/js/ionic.bundle.min',
},
shim: {
ionic : {exports : 'ionic'}
},callback: function () {
'use strict';
require([
'angular',
'route',
'app'
], function (angular) {
// init app
angular.bootstrap(document, ['app']);
});
}
});
app.js
define(['ionic',
'./LoginCtrl',],
function (angular) {
'use strict';
var app = angular.module('app', [
'ionic','app.controllers']);
return app;
});
LoginCtrl.js
/*global define, console */
define(['angular'], function (ng) {
'use strict';
return ng.module('app.controllers', ['$scope','$state'
,function ctrl($scope, $state) {
$scope.login = function () {
alert("Login is clicked")
};
}]);
});
You can follow the tips here - https://www.startersquad.com/blog/angularjs-requirejs/
I am trying to create a very simple Angular + Require project template.
I am getting error-
Error: Script error for: ngRoute
http://requirejs.org/docs/errors.html#scripterror
In my index.html i have
require(
[
'jquery',
'angular',
'mainApp',
], function($, angular, mainApp) {
var AppRoot = angular.element(document.getElementById('CollectorWallApp'));
AppRoot.attr('ng-controller','MainController');
angular.bootstrap(AppRoot, ['MainApp']);
});
In mainApp.js i'm doing the following-
'use strict';
define(['angular','ngRoute'],function(angular,ngRoute){
var MainApp = angular.module('MainApp',['ngRoute']);
MainApp.controller("MainController", function ($scope) {
console.log("Main Controller working");
});
//Route configuration goes here
MainApp.config([ '$routeProvider', function ($routeProvider) {
console.log("--->checkiing out $routeProvider");
}]);
return MainApp;
});
In Require config
'paths': {
'angular': 'js/lib/angular/angular',
'ngRoute': 'js/lib/angular-route.min',
.
.
.
.
.
'shim': {
'angular': {
exports: 'angular',
},
'ngRoute': {
exports: 'ngRoute',
deps: ['angular']
},
Unable to debug or pin point the reason.
Note- all my require paths are correct. Kindly help. Thanks