I'm using AngularJS and requireJS and I'm using this seed template to help me to get Angular to place nicely with requireJS which can be found here LINK
At the moment I'm trying to integrate AngularUI's calendar into the project but I keep recieving the error "Cannot call method 'map' of undefined" when the calendar code is in calendarCtrl.js with the scope injected into this controller. However when I place the code directly in the controller (controllers.js) the calendar works.
Plunkr link: LINK
In angular the internal injectors for all of the scope controls are initialized by the app. You managed to detach your app from your controller definition so angular didn't know how to inject the pieces needed for the use of the $scope object.
Option 1
So to get this to work so you need to either define an app/module that get's passed into the space where the control is defined:
define(['angular'], function (angular) {
'use strict';
return angular.module('TP.controllers', []);
});
calendar control:
define([
"jquery",
"controllers",
"jqueryui",
"full_calendar",
"calendar",
],
function($, controllers) {
return controllers
.controller('calendarCtrl', ['$scope', function($scope) {
....
In which case you'd have to include every individual controller in your top level application like:
define([
'angular',
'controllers',
'calendarCtrl',
'full_calendar',
'calendar'
], function (angular, controllers) {
'use strict';
return angular.module('TP', ['TP.controllers', 'ui.calendar']);
});
Which to some degree defeats the purpose of using AMD.
Option 2
A better option is to define your calendar as it's own module then define it as a child of controllers. This maintains the angular injection chain so the scope has the proper context when initializing the calendar actions.
Defining the controllers root:
define(['angular', 'calendarCtrl'], function (angular) {
'use strict';
return angular.module('TP.controllers', ['calendarCtrl']);
});
Defining the calendar controller:
define([
"jquery",
"angular",
"jqueryui",
"full_calendar",
"calendar",
],
function($, angular) {
return angular.module('calendarCtrl', [])
.controller('calendarCtrl', ['$scope', function($scope) {
...
Working plunker of this version at http://plnkr.co/edit/Xo41pqEdmB9uCUsEEzHe?p=preview.
Related
I am trying to get angularjs to play nicely with local templates that override bootstrap ones.
I had initially use the same file path (uib/template/carousel/carousel.html for example) which is fine when published, but locally it doesn't work.
So, I found this soluton:
Angular ui bootstrap directive template missing
They have said you can override the template with a new url with the $provide service.
So I have done this:
'use strict';
angular.module('core').config(coreConfig);
function coreConfig($provide) {
$provide.decorator('uibCarousel', function ($delegate) {
console.log($delegate[0]);
$delegate[0].templateUrl = 'bootstrap/carousel/carousel.html';
return $delegate;
});
};
which should work.
my core module looks like this:
'use strict';
angular.module('core', [
'ngCookies',
'ngNotify',
'ngResource',
'ngSimpleCache',
'ui.bootstrap',
'ui.bootstrap.tpls',
'ui.router',
'ui.select',
// -- remove for brevity -- //
]);
As you can see, I have the ui.bootstrap.tpls module loaded, so in theory, my code should work.
Can anyone think of a reason that it won't?
Sorry for all the comment spam. I think I have found the answer to your issue.
You must append Directive to a directive when defining the decorator:
function coreConfig($provide) {
$provide.decorator('uibCarouselDirective', function ($delegate) {
console.log($delegate[0]);
$delegate[0].templateUrl = 'bootstrap/carousel/carousel.html';
return $delegate;
});
};
From the docs:
Decorators have different rules for different services. This is
because services are registered in different ways. Services are
selected by name, however filters and directives are selected by
appending "Filter" or "Directive" to the end of the name. The
$delegate provided is dictated by the type of service.
https://docs.angularjs.org/guide/decorators
This is an example from my own (working) code:
$provide.decorator("uibDatepickerPopupDirective", [
"$delegate",
function($delegate) {
var directive = $delegate[0];
// removed for brevity
return $delegate;
}
]);
Is there any way that I get regestered controllers name in my angularjs module?
I implement Lazy Loading controller in my sample and I want test my code .
I recommend using an IIFE structure like so:
(function() {
angular.module( 'MyApp', [
'dependency',
]);
a controller function would simply look like this:
function SomeCtrl($scope, ...) {
};
and then at the bottom of your page:
angular
.module('MyApp')
.controller('SomeCtrl', SomeCtrl)
})();
In test cases (e.g. Jasmine), you will be able to access the ctrl by its name.
I'm trying for the first time to use AngularJS in conjunction with RequireJS using this guide as a basis. As far I can tell after a lot of debugging I'm loading all my modules in the correct order, but when the application runs Angular throws an Error / Exception with the following message:
Argument 'fn' is not a function, got string from myApp
I've seen this message before due to syntax errors, so even though I've looked trough the code multiple times I won't rule out the possibility of a simple syntax error. Not making a Fiddle just yet in case it is something as simple as a syntax error, but I'll of course do so if requested.
Update: I just noticed when setting ng-app="myApp" in the <html> tag I also get an additional error,
No module: myApp
Update II: Okay, it turns out it indeed was an syntax error in the only file not included below. I am though still left with the problem from update I.
RequireJS bootstrap
'use strict';
define([
'require',
'angular',
'app/myApp/app',
'app/myApp/routes'
], function(require, ng) {
require(['domReady'], function(domReady) {
ng.bootstrap(domReady, ['myApp']);
});
});
app.js
'use strict';
define([
'angular',
'./controllers/index'
], function(ng) {
return ng.module('myApp', [
'myApp.controllers'
]);
}
);
controllers/index
'use strict';
define([
'./front-page-ctrl'
], function() {
});
controllers/module
'use strict';
define(['angular'], function (ng) {
return ng.module('myApp.controllers', []);
});
controllers/front-page-ctrl
'use strict';
define(['./module'], function(controllers) {
controllers.
controller('FrontPageCtrl', ['$scope',
function($scope) {
console.log('I\'m alive!');
}
]);
});
Delete ng-app="myApp" from your html.
Because it has bootstrapped manually
ng.bootstrap(domReady, ['myApp']);
RequireJS docs on Dom ready state:
Since DOM ready is a common application need, ideally the nested
functions in the API above could be avoided. The domReady module also
implements the Loader Plugin API, so you can use the loader plugin
syntax (notice the ! in the domReady dependency) to force the
require() callback function to wait for the DOM to be ready before
executing. domReady will return the current document when used as a
loader plugin:
So, when you require 'domReady' the result is a function:
function domReady(callback) {
if (isPageLoaded) {
callback(doc);
} else {
readyCalls.push(callback);
}
return domReady;
}
But when you append the domReady string with ! sign the result will be the actual document element:
'use strict';
define([
'require',
'angular',
'app/myApp/app',
'app/myApp/routes'
], function(require, ng) {
require(['domReady!'], function(domReady) {
// domReady is now a document element
ng.bootstrap(domReady, ['myApp']);
});
});
I'm in the beginning stages of building a large app with AngularJS and RequireJS. Everything loads find but directives aren't manipulating the DOM as they should. No errors are being reported and rest of the app works fine: Views are loaded and $scope is bindable. Examining the console shows that all the files loaded. I'm assuming this is a lazy load issue in that my directive is simply not loading at the correct time. I'd appreciate any insight into how to properly load directives in this regard. Unless it's a part of Angular's jqLite, please refrain from suggesting jQuery.
config.js
require.config({
paths: { angular: '../vendor/angular' }
shim: { angular: { exports: 'angular' } }
});
require(['angular'], function(angular) {
angular.bootstrap(document, ['myApp']);
});
myApp.js
define(['angular', 'angular-resource'], function (angular) {
return angular.module('myApp', ['ngResource']);
});
routing.js
define(['myApp', 'controllers/mainCtrl'], function (myApp) {
return myApp.config(['$routeProvider', function($routeProvider) {
...
}]);
});
mainCtrl.js
define(['myApp', 'directives/myDirective'], function (myApp) {
return myApp.controller('mainCtrl', ['$scope', function ($scope) {
...
}]);
});
myDirective.js
require(['myApp'], function (myApp) {
myApp.directive('superman', [function() {
return {
restrict: 'C',
template: '<div>Here I am to save the day</div>'
}
}])
});
home.html
<div class="superman">This should be replaced</div>
home.html is a partial that's loaded into ng-view
Angular cannot load directives after it has been bootstrapped. My suggestion is:
Make myDirective.js do a define(), not a require()
Make sure myDirective.js is run before the require(['angular'],...) statement in config.js, e.g. do require(['angular','myDirective'],...). For this to work, myDirective should be shimmed to depend on angular - thanks # David Grinberg.
As a sidenote, take a look at this in Stackoverflow/this in GitHub, we have been trying to do RequireJS + Angular play together.
i have a weird problem regarding angular resource. when i try to define it it causes the app to create an error. i dunno but is this the correct style of defining an angular Resource? tIA
main.js
'use strict';
require.config({
paths: {
jquery: 'libs/jquery/jquery-1.9.1',
angular: 'libs/angular/angular.min',
ngResource: 'libs/angular/angular-resource.min'
},
shim: {
angular: {
exports: 'angular'
},
resource : { deps : ['angular'], 'exports' : 'ngResource'},
}
});
require([
'jquery',
'angular',
//'ngResource',
'app',
'routes',
],
function ($, angular, app, routes) {// set main controller
$(function(){
var $html = $('html');
angular.bootstrap($html, [app['name']]);
$html.addClass('ng-app');
});
});
Just to help out those users who are not familiar with the code above; The code shows RequireJS configuration and initialization structure, and only a small part at the end is the actuall AngularJS code.
You have correctly configured RequireJS to include ngResource before initialization, but you didn't actually tell Angular to use it.
I'm not sure what app['name'] stands for, but your angular bootstrap call should include the ngResource module:
angular.bootstrap($html, ['ngResource']);
And, btw, I don't think you need to add the class ('ng-app') at the end.
In your callback when all resources are loaded, try to explicitly define the modules and dependancies before bootstrapping, like this:
angular.module('fooApp', ['ngResource']); // Module name and list of dependancies.
angular.bootstrap(document, 'fooApp');
There is no need to manually add the ng-app class, when this class is used to do bootraping automatically, witch is not what you want. You want to load the applicatiopns module when all scripts are loaded, with the ngResource module as a dependancy.
Hope this helps.