I went through this tutorial. Now I am attempting incorporate require
I found this explanation.
I am currently getting an error
Object #<Object> has no method 'unshift'
Here is the code that is causing the error
require(['jquery', 'angular', 'app/routes/app'], function ($, angular, mainRoutes) {
//tried this way as well
//$(function () { // using jQuery because it will run this even if DOM load already happened
// angular.bootstrap(document, ['mainApp']);
//});
require(['Scripts/app/modules/mainApp.js'], function (mainApp) {
angular.bootstrap(document.body, [mainApp]);//based of orginal answer
})
});
my app.js file
define(['app/modules/mainApp', 'app/controller/controllers'], function (mainApp) {
return mainApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/phones', {
templateUrl: 'Templates/phone-list.html',
controller: 'PhoneListCtrl'
}).
when('/phones/:phoneId', {
templateUrl: 'Templates/phone-detail.html',
controller: 'PhoneDetailCtrl'
}).
otherwise({
redirectTo: '/phones'
});
}]);
});
and my mainApp.js file
define(['angular', 'angular-resource'], function (angular) {
return angular.module('mainApp', ['ngResource']);
});
there are other files that I didnt show (controllers, services) but I dont think the problem lies their
UPDATE
I am now getting an error of undefined injector.
This is the only break point that gets hit, but the item is not undefined.
UPDATE 2
I updated my project to more resemble this
my main.js now is this
require.config({
baseUrl: '/Scripts/',
urlArgs: "bust=" + (new Date()).getTime(),
paths: {
'jquery': 'lib/require-jquery',
'angular': 'lib/angular/angular.min',
'angular-resource': 'lib/angular/angular-resource.min',
},
shim: {
'angular': { 'exports': 'angular' },
'angular-resource': { deps: ['angular'] },
'jQuery': { 'exports': 'jQuery' },
},
priority: [
'angular'
]
});
require(['angular', 'app/modules/app', 'app/routes/routes'], function (angular, app, routes) {
var $html = angular.element(document.getElementsByTagName('html')[0]);
angular.element().ready(function () { //breakpoint here
$html.addClass('ng-app');
angular.bootstrap($html, [app.name]);
});
});
if i put a break point on angular element and run a test in console
(app == routes)
true
should app be equal to routes?
The second argument of bootstrap method should be an array, I made the change on the code below.
require(['jquery', 'angular', 'app/routes/app'], function ($, angular, mainRoutes) {
//tried this way as well
//$(function () { // using jQuery because it will run this even if DOM load already happened
// angular.bootstrap(document, ['mainApp']);
//});
require(['Scripts/app/modules/mainApp.js'], function (mainApp) {
angular.bootstrap(document.body, [mainApp]);
})
});
Related
I am using requireJs in my app. I face a scenario and I want to clear it out.
I'm loading the particular template (views) and their dependent js files based on location url or routes. See Following code example.
routes: {
'/': {
templateUrl: 'views/login.html',
dependencies: [
'scripts/controllers/login.js',
]
},
'/abc-view': {
templateUrl: 'views/abc.html',
requireLogin: true,
dependencies: [
'scripts/controllers/abc.js',
'scripts/controllers/xyz.js',
]
},
'/xyz-view': {
templateUrl: 'views/xyz.html',
requireLogin: true,
dependencies: [
'scripts/controllers/xyz',
}
}
When I change to xyz view then xyz.js file will be loaded. My question is when I change to abc view does the xyz.js will be loaded if yes then will it be loaded from cache ?
I have seen in newtwork tab it loads the same file i.e xyz.js again, not from cache same with the html templates that are already included in one template with ng-inlcude it does not loads from cache.
Any help will be appreciated. Thanks.
flow of my application is as following:
index.html have
<script type="text/javascript" src="libs/requirejs/require.js" data-main="config.js"></script>
In Config.js I'm manually bootstrapping the app.
requirejs.config({
"paths":{
"angular": "libs/angular/angular.min",
"angular-route":"libs/angular-route/angular-route",
"angular-sanitize":"libs/angular-sanitize/angular-sanitize",
"jquery-ui":"libs/jquery-ui/jquery-ui.min",
"ngAnimate":"libs/angular-animate/angular-animate.min",
"angularSrapCore":"libs/angular-strap/dist/angular-strap.min",
"angularStrap":"libs/angular-strap/dist/angular-strap.tpl.min"
},
"shim": {
"angular": {
"exports": "angular"
},
"drutasApp": {
deps: ["angular", "angular-route","angular-sanitize","jquery-ui","ngAnimate"]
},
"angular-route": {
deps: ["angular"]
}
}
});
require(['angular','app'
], function (angular) {
angular.element(document).ready(function () {console.log("app bootstraped");
angular.bootstrap(document, ['app']);
});
});
app.js is in same directory with the config.js, code is following...
define(['scripts/routes.js','scripts/services/dependencyResolverFor.js'], function(config, dependencyResolverFor)
{
var app = angular.module('app', ['ngRoute','ngAnimate','ngSanitize']);
app.config(
[
'$routeProvider',
'$locationProvider',
'$controllerProvider',
'$compileProvider',
'$filterProvider',
'$provide',
function($routeProvider, $locationProvider, $controllerProvider, $compileProvider, $filterProvider, $provide)
{
app.controller = $controllerProvider.register;
app.directive = $compileProvider.directive;
app.filter = $filterProvider.register;
app.factory = $provide.factory;
app.service = $provide.service;
app.constant = $provide.constant;
$locationProvider.html5Mode(false);
if(config.routes !== undefined)
{
angular.forEach(config.routes, function(route, path)
{
$routeProvider.when(path, {
templateUrl:route.templateUrl,
resolve:dependencyResolverFor(route.dependencies)
});
});
}
if(config.defaultRoutePaths !== undefined)
{
$routeProvider.otherwise({redirectTo:config.defaultRoutePaths});
}
}
]);
return app;
});
`routes.js` is as following...
define([], function()
{
return {
defaultRoutePath: '/',
routes: {
'/': {
templateUrl: 'views/home.html',
dependencies: [
'scripts/controllers/home'
]
},
'/abc-view': {
templateUrl: 'views/abc.html',
dependencies: [
'scripts/controllers/abc',
'scripts/controllers/xyz'
]
},
'/xyz-view': {
templateUrl: 'views/xyz.html',
dependencies: [
'scripts/controllers/xyz'
]
}
}
};
});
dependencyResolver.js
define([], function()
{
return function(dependencies)
{
var definition =
{
resolver: ['$q','$rootScope', function($q, $rootScope)
{
var deferred = $q.defer();
require(dependencies, function()
{
$rootScope.$apply(function()
{
deferred.resolve();
});
});
return deferred.promise;
}]
}
return definition;
}
});
My question is when I change to abc view does the xyz.js will be loaded
No, requireJS will judge on the final URL of the script tag going to be fetched. If it is already loaded before, requireJS won't do anything.
if yes then will it be loaded from cache ?
Not likely cache got to be used, but requireJS simply detect if the same file with same URL got loaded before or not. If it is loaded before, requireJS will just execute your js without loading anything.
I have seen in newtwork tab it loads the same file i.e xyz.js again, not from cache same with the html templates that are already included in one template with ng-inlcude it does not loads from cache.
As looking into your code, requireJS got to use to fetching the dependencies. And this behavior cannot happen, unless requirejs.undef() got called somewhere. Or that is an old version of requireJS where module's URL was not tracking and <script> got to be loaded regardless the conditions.
NOTE I am not sure about the behavior of older version than 2.1.x of requireJS.
I am using angular js with require js to make a single page template.
Everything is working accept one thing. When I am trying to define controller name in $routeProvider, it shows an error:
Error: [ng:areq] http://errors.angularjs.org/1.4.8/ng/areq?p0=SignIn&p1=not%20aNaNunction%2C%20got%20undefined
I separate the files like that:
rootfolder
js
-require.js
-angular.min.js
-angular-route.js
-main.js
-app.js
-signin.js
-signup.js
index.php
sign_in.php
sign_up.php
My code:
Main.js
require.config({
baseUrl: "./js",
paths: {
'angular': 'angular.min',
'angularRoute': 'angular-route'
},
shim: {
'angular' : { exports : 'angular' },
'angularRoute' : { deps : ['angular'] }
},
deps: ['app']
});
App.js
define(['angular','angularRoute'], function (angularRoute) {
var app = angular.module('webapp', ['ngRoute']);
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/signin', {
templateUrl: 'sign_in.php',
controller: 'SignIn'
}).
when('/signup', {
templateUrl: 'sign_up.php',
controller: 'SignUp'
}).
otherwise({
redirectTo: '/signin'
});
}
]);
return app;
});
controller - signin.js
define(['app'], function (app) {
app.controller('SignIn', function ($scope) {
$scope.message = "Sign in page";
});
});
controller - signup.js
define(['app'], function (app) {
app.controller('SignUp', function ($scope) {
$scope.message = "Sign up page";
});
});
When I define controller: 'SignIn' or controller: 'SignUp' in $routeProvider it shows an error otherwise it works fine.
You need to make requirejs include signin.js and signup.js, too. The code you have in App.js does not trigger any requirejs calls to load these two files.
when('/signin', {
templateUrl: 'sign_in.php',
controller: 'SignIn'
})
only tells AngularJS to try and instantiate the controller called 'SignIn' once you navigate to /signin. However, this will not result in the loading of the signin.js file.
Make sure to have your outer most module to depend on signin and signup, too.
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 want to load controllers on the fly when needed rather than loading them in one go. So, for the I've implemented dynamic approach which works fine without any error. It also works well with Ui-Router.
But the problem is in Index.html page. I want to put global (super parent) controller name "appCtrl". As this appCtrl should be initialized when I run my app. For that I need to write like ng-controller="appCtrl" or ng-controller="appCtrl as vm" at body tag.
But when I do it, it gives error that appCtrl is a function, got undefined. I tried sever ways but still unable to identify exact error. I have working on this issue since two to three days but still not able to identify it.
I have made this plunker.
look at body tag of index.html.
main.js
require.config({
paths: {
"angular": "//cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.0-rc.1/angular",
"ui-router": "//rawgit.com/angular-ui/ui-router/0.2.15/release/angular-ui-router"
},
shim: {
"angular": {
exports: 'angular'
},
"ui-router": {
deps: ['angular']
}
}
});
define(
['angular',
'app',
'controllers/appCtrl'],
function (angluar, app) {
angular.bootstrap(document, ['MyApp'])
});
app.js
define([
'angular',
'ui-router'
], function (angular) {
var app = angular.module('MyApp', ['ui.router']);
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) {
$stateProvider
.state("home", {
url: "/",
controller: 'homeCtrl',
controllerAs: 'vm',
templateUrl: 'views/homeView.html',
resolve: lazyProvider.resolve('homeCtrl')
});
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;
});
Index.html
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.17/require.js" data-main="main.js"></script>
</head>
<body ng-controller="appCtrl as vm"> // I want this to work correctly but it is not getting loaded dynamically. I don't know why. Help me to resolve it.
<a ui-sref="home">go home</a>
<ui-view></ui-view>
{{vm.appVar}}
</body>
</html>
You are actually missing the controller statement in your controller code.
Use the following code
define(['app'], function (app){ //Updated Line
console.log('app controller loaded');
app.controller('appCtrl',ctrl); //New Line added
ctrl.$inject = ['$http'];
function ctrl ($http) {
this.appVar = 'hi from appCtrl';
};
return ctrl;
});
See the plunker
Having created a very basic prototype AngularJS project, I wanted to migrate it to use RequireJS to load the modules. I modified my app based on the AngularAMD and AngularAMD-sample projects.
Now, when I access my default route I get:
Uncaught TypeError: Cannot read property 'directive' of undefined
I've been scratching my head as to why the dependency on 'app' is not being satisfied. If anyone can spot what I'm obviously doing wrong, it'd be much appreciated.
I've put the source code of my project here on GitHub, but here's the key parts:
main.js
require.config({
baseUrl: "js/",
// alias libraries paths
paths: {
'angular': '../bower_components/angular/angular',
'angular-route': '../bower_components/angular-route/angular-route',
'angular-resource': '../bower_components/angular-resource/angular-resource',
'angularAMD': '../bower_components/angularAMD/angularAMD',
'ngload': '../bower_components/angularAMD/ngload',
'jquery': '../bower_components/jquery/jquery'
},
// Add angular modules that does not support AMD out of the box, put it in a shim
shim: {
'angularAMD': ['angular'],
'ngload': [ 'angularAMD' ],
'angular-route': ['angular'],
'angular-resource': ['angular']
},
// kick start application
deps: ['app']
});
app.js
define(['angularAMD', 'angular-route', 'controller/login', 'controller/project_detail', 'controller/project_list'], function (angularAMD) {
'use strict';
var app = angular.module('cmsApp', ['ngRoute']);
app.constant('REMOTE_BASE_URL', "/cms/v2/remote");
app.constant('SERVER_ERROR_TYPES', {
authentication: 'Authentication',
application: 'Application',
transport: 'Transport'
});
app.constant('AUTH_ERROR_TYPES', {
invalidLogin: "INVALID_CREDENTIALS",
invalidToken: "INVALID_TOKEN",
noToken: "NO_TOKEN"
});
app.constant('AUTH_EVENTS', {
loginSuccess: 'auth-login-success',
loginFailed: 'auth-login-failed',
logoutSuccess: 'auth-logout-success',
notAuthenticated: 'auth-not-authenticated'
});
app.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/login', {
templateUrl: 'partials/login.html',
controller: 'LoginCtrl'
}).
when('/projects', {
templateUrl: 'partials/project-list.html',
controller: 'ProjectListCtrl'
}).
when('/projects/:projectId', {
templateUrl: 'partials/project-detail.html',
controller: 'ProjectDetailCtrl'
}).
otherwise({
redirectTo: '/projects'
});
}]);
return angularAMD.bootstrap(app);
});
And the file which the exception is being raised in:
login_form.js
define(['app'], function (app) {
app.directive('loginForm', function (AUTH_EVENTS) {
return {
restrict: 'A',
template: '<div ng-if="visible" ng-include="\'partials/login.html\'">',
link: function (scope) {
scope.visible = false;
scope.$on(AUTH_EVENTS.notAuthenticated, function () {
scope.visible = true;
});
scope.$on(AUTH_EVENTS.loginFailed, function () {
alert("An error occured while trying to login. Please try again.")
scope.visible = true;
});
scope.$on(AUTH_EVENTS.logoutSuccess, function () {
scope.visible = true;
});
}
};
});
});
You are loading 'controller/login' before the app itself was created.
Probably it is better to create a separate module like
define(['directive/login_form', 'service/authentication'], function () {
'use strict';
var loginModule = angular.module('loginModule', []);
loginModule.controller('LoginCtrl', ...
loginModule.directive('loginForm', ...
and then do something like
var app = angular.module('cmsApp', ['ngRoute', 'loginModule']);
Does that make sense?
UPDATE:
I am just thinking of another solution. Just remove 'controller/login' from your app define. Using angularAMD your controller should not be loaded anyway before you navigate to the specified url. Just remove it and your controller gets loaded on demand. That way, app will be defined! (Although I would still suggest to create multiple modules. It feels better to not have everything in the app module but have multiple modules for different responsibilities. Also much better for testing.)
angularAMD.route({
templateUrl: 'views/home.html',
controller: 'HomeController',
controllerUrl: 'scripts/controller'
})
Note the field controllerUrl.
Have a look here.