Im new to Angularjs and i am trying to integrate with my application that uses RequireJS. I have the application working on a test page using the ng-submit. However, in my app.js file i dont think i am "require"ing my controllers in the best way.
I am using AngularJS v1.1.5
Here's my tree:
resources
- CSS
- js
- controllers
- TestController1.js
- TestController2.js
- TestController3.js
- TestController4.js
- TestController5.js
- libs
- angular.js
- jquery.js
- require.js
- mondernizr.js
......
......
......
main.js
app.js
pages
test1.html
test2.html
test3.html
test4.html
test5.html
main.js
(function(require) {
'use strict';
require.config({
baseUrl: '/libs',
paths: {
'zepto' : 'zepto',
'jquery' : 'jquery',
'angular' : 'angular',
'router' : 'page',
'history' : 'history.iegte8',
'event' : 'eventemitter2'
},
shim: {
'zepto' : { exports: '$' },
'angular' : { deps: ['jquery'], exports: 'angular' },
'app' : { deps: ['angular'] },
'router' : { exports: 'page'},
'modernizr' : { exports: 'Modernizr' }
}
});
require(['angular', 'app'], function(angular) {
'use strict';
angular.bootstrap(document, ['app']);
});
})(this.require);
app.js
define("app", ["angular"], function(angular){
var app = angular.module("app", []);
app.config(function($routeProvider, $locationProvider){
$routeProvider
.when("/test1", {
templateUrl: "test1.html",
controller: "TestController1"
})
.when("/test2", {
templateUrl: "test2.html",
controller: "TestController2"
})
.when("/test3", {
templateUrl: "test3.html",
controller: "TestController3"
})
.when("/test4", {
templateUrl: "test4.html",
controller: "TestController4"
})
.when("/test5", {
templateUrl: "test5.html",
controller: "TestController5"
})
.otherwise({ redirectTo: '/test1'});
});
return app;
});
require(["app", "controllers/TestController1"]);
require(["app", "controllers/TestController2"]);
require(["app", "controllers/TestController3"]);
require(["app", "controllers/TestController4"]);
require(["app", "controllers/TestController5"]);
TestController1-5.js
require(['app'], function(app) {
app.controller("TestController1", function($scope) {
$scope.clickMe = function() {
alert('TestController1.js is responding');
$scope.title = "Title";
$scope.data = {message: "Hello"};
$scope.message = "Hello World!";
};
});
});
test1-5.html
<div ng-controller="TestController1">
<form ng-submit="clickMe()">
<div>
<button type="submit">Test TestController1</button>
</div>
</form>
{{ data.message + " world" }}
{{ title }}
</div>
Equally if you think there are other ways i can improve my code and code structure feel free to suggest.
Thanks
Maybe you could just improve your code by making an "app.controllers" module that will be in charge of loading all your controllers. Then in your app.js, you just add this module as dependency.
So for instance.
app/controllers/MyController.js:
define(['angular'], function(angular) {
return angular.module('app.controllers.MyCtrl', [])
.controller('MyCtrl', [function(){
[...]
}]);
app/controllers.js:
define([
'angular',
'app/controllers/MyController'
],
function(angular) {
return angular.module('app.controllers', [
'app.controllers.MyCtrl'
]);
});
app/app.js:
define("app", "app/controllers", ["angular"], function(angular){
var app = angular.module("app", ['app.controllers']);
app.config(function($routeProvider, $locationProvider){
$routeProvider
.when("/my", {
templateUrl: "my.html",
controller: "MyCtrl"
})
.otherwise({ redirectTo: '/test1'});
});
return app;
});
You could also load controllers asynchronously this way for instance:
angular.module('myApp.controllers', [])
.controller('MyCtrl', ['$scope','$injector', function($scope, $injector){
require(['app/controllers/MyController'], function(MyCtrl){
$injector.invoke(MyCtrl, this,{'$scope':$scope});
});
}]);
The downpoint of this kind of loading is that you will have to manually call $scope.$apply(); in order to manually ask for a digest otherwise your scope modifications on this controller will not be taken into account as it is with "standard" loading.
However, I will not recommend this kind of loading. In the end when the code is minified and optimized in one file with r.js, it does not make much sense to "lazy load" code.
Related
I am trying to configure an web app with requireJS and angularJS. I come from marionette configuration and I am trying to have a similar one in angular (in concepts like views and controllers) first so I want to be able to map #/test to my controller and log in the console one message.
I've seen Does AngularJS support AMD like RequireJS? and RequireJS and AngularJS and I kind of got the differences and from my point of view my config should work... but it does not...
Here is my code:
File: app.config.js
require.config({
shim: {
angular: {
exports: 'angular'
},
angularRoute: ['angular']
},
paths: {
angular: '../lib/angular',
angularRoute: '../lib/angular-route'
}
});
require(['angular', 'app', 'routes/index'], function (angular) {
angular.bootstrap(document, ['app']);
});
File: app.js
define(['angular', 'angularRoute'], function (angular) {
//angular.module('app.controllers', []);
var app = angular.module('app', ['ngRoute']);
return app;
});
File: routes/index.js
define(['angular', 'app', 'controllers/index'], function (angular, app) {
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/', { templateUrl: require.toUrl('/resources/js/app/templates/test.html'), controller: 'indexController'});
}]);
});
File: controllers/index.js
define(['angular', 'app'], function (angular, app) {
//var appControllers = angular.module('app.controllers');
app.controller('indexController', ['$scope', function ($scope) {
console.log('cascade...');
}]);
});
What am i missing? When i access #/test, i don't see "cascade" in the console, should I?.. Right?
Thanks in advance.
I have a module App and factory i18n, what is the best way to call i18n.load
method form App (config? run? etc?)
angular
.module('App', [
'ngRoute',
'service.i18ndb'
])
.config(function ($routeProvider) {
//want to i18n.load() here somehow
$routeProvider
.when('/signin', {
templateUrl: '../views/sign-in.html',
controller: 'SigninCtrl'
})
.when('/mix', {
templateUrl: '../views/mix.html',
controller: 'MixCreateCtrl'
})
.otherwise({
redirectTo: '/signin'
});
});
angular.module('App')
.factory('service.i18ndb', function() {
return {
load: function() { console.log("Busy"); }
}
}
);
The problem you will always have if you use .run is having to deal with a page that has no i18n loaded. This means you will need to have a way to deal with your view when their is no i18n loaded. You can either hide it or the text will flash with the wrong values at first.
However, AngularJS gives you a wonderful feature to make sure it is loaded before your view is loaded: the resolver!
Here is how to do it.
var i18nResolver = function(service.i18ndb) {
return service.i18ndb.promise;
};
$routeProvider
.when('/signin' {
templateUrl: '../views/sign-in.html',
controller: 'SigninCtrl',
resolve: {
i18n: i18nResolver
}
});
You can fix this code to use the correct promise of your HTTP request or whatever service you are using.
One of the benefits of using this way is you can have a different labels for a different page for your i18n and use the i18n service to recover them no matter where you are.
You are defining your app module twice. One you create your factory, it can be injected to the controller and used there. You could try something like this:
angular.module('App', ['ngRoute','service.i18ndb'])
.factory('service.i18ndb', function() {
return {
load: function() { console.log("Busy"); }
}
})
.config(function ($routeProvider) {
//want to i18n.load() here somehow
$routeProvider
.when('/signin', {
templateUrl: '../views/sign-in.html',
controller: 'SigninCtrl'
})
.when('/mix', {
templateUrl: '../views/mix.html',
controller: 'MixCreateCtrl'
})
.otherwise({
redirectTo: '/signin'
});
})
.controller('SigninCtrl', function($scope, service.i18ndb) {
// Call your factory function here
service.i18ndb.load();
// If the function returns a value you could assign it to a scope
// variable so it can be used in your template 'sign-in.html'
$scope.your_variable = service.i18ndb.load();
});
angular
.module('App', [
'ngRoute'
])
.config(function ($routeProvider) {
//want to i18n.load() here somehow
$routeProvider
.when('/signin', {
templateUrl: '../views/sign-in.html',
controller: 'SigninCtrl'
})
.when('/mix', {
templateUrl: '../views/mix.html',
controller: 'MixCreateCtrl'
})
.otherwise({
redirectTo: '/signin'
});
})
.run(['i18ndb', function(i18ndb) {
i18ndb.load();
}])
.factory('i18ndb', function() {
return {
load : function() {console.log('test')}
};
});
);
You were requiring a module which has not been defined (as far as I can tell). The factory you were adding was on the 'App' module not the 'service.i18ndb'.
You then need to dependency inject the i18ndb factory in to the run method to call it from there (presuming that you want to call that function to bootstrap your app).
The AngularJS-RequireJS app im building is throwing Uncaught Error: [$injector:modulerr] Failed to instantiate module myApp due to:
Error: [$injector:unpr] Unknown provider: e error after r.js optimization . The problem didnt exist before . I followed a similar question at this link and added mainConfigFile to the build file , but still the problem persists . Here are the codes the respective files
build.js
({
mainConfigFile:'js/main.js',
appDir: "./",
baseUrl: "js",
dir: "/home/karthic/optimized-test",
modules: [
{
name: "main"
}
]
})
main.js
require.config({
baseUrl: './js',
paths: {
angular: 'libs/angular-1.2.9',
angularRoute: 'libs/angular-route-1.2.9'
},
shim: {
'angularRoute': {
deps: ['angular'],
exports: 'angularRoute'
},
'angular': {
exports: 'angular'
}
}
});
require(['angular', 'controller', 'ang_when_routes', 'angularRoute'], function(angular, controller, angWhenRoutes, angularRoute) {
'use strict';
var app = angular.module('myApp', ['ngRoute']);
angular.element(document).ready(function() {
angular.bootstrap(document, ['myApp']);
});
angWhenRoutes.initRoutes(app);
controller.controllerInit(app);
});
controller.js
define(function() {
function controllerInit(app) {
console.log('inside func cont');
app.controller('mapApp', function($scope, $http, $location) {
console.log('inside mapp,testing r.js optimizer');
});
}
return {
controllerInit: controllerInit
}
});
ang_when_routes.js
define(function() {
function initRoutes(app) {
app.config(
function($routeProvider, $httpProvider) {
$httpProvider.defaults.withCredentials = true;
$routeProvider.
when('/', {
templateUrl: 'index_content.html',
controller: 'mapApp'
})
});
}
return {
initRoutes: initRoutes
}
});
index.html
<!DOCTYPE html>
<html>
<head>
<title>Optimizer error</title>
<script data-main="js/main.js" src="js/libs/require.js"></script>
</head>
<body>
<div ng-view>
</div>
</body>
</html>
index_content.html
<p>Testing the r optimizer</p>
It'll be really helpful for me if the error can be fixed
Here is the answer as suggested by #radimKohler in the first comment . To avoid issues with angularJS during minification Inline array Annotation has to be used as referred in the Angular Documentation . Here is the modified code after the change
controller.js
define( function () {
function controllerInit(app) {
console.log('inside func cont');
app.controller('mapApp',['$scope','$http','$location', function ($scope, $http, $location) {
console.log('inside mapp,testing r.js optimizer');
}]);
}
return {
controllerInit: controllerInit
}
});
ang_when_routes.js
define(function(){
function initRoutes(app){
app.config(['$routeProvider','$httpProvider',
function($routeProvider,$httpProvider){
$httpProvider.defaults.withCredentials = true;
$routeProvider.
when('/',{
templateUrl:'index_content.html',
controller:'mapApp'
})
}]);
}
return {
initRoutes:initRoutes
}
});
I'm trying to figure out how to use PouchDB in AngularJS. I'm trying to follow these instructions https://github.com/wspringer/angular-pouchdb
I think I'm having a problem understanding the syntax for creating factories and/or services. I get as far as the section on "Interacting with the database"
app.js
'use strict';
angular
.module('myappApp', [
'ngCookies',
'ngResource',
'ngSanitize',
'ngRoute',
'pouchdb'
])
.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
})
.otherwise({
redirectTo: '/'
});
})
angular.factory('someservice', function(pouchdb) {
// Do something with pouchdb.
var db = pouchdb.create('testdb');
pouchdb.destroy('testdb');
db.put({_id: 'foo', name: 'bar'});
});
When I add the "db.put", The message I see in the browser's console is:
[15:17:45.343] TypeError: angular.factory is not a function # http://127.0.0.1:9000/scripts/app.js:21
The angular object does not have a factory method, so it will returned as undefined.
Try putting it on the object returned by the module method.
angular
.module('myappApp', [
'ngCookies',
'ngResource',
'ngSanitize',
'ngRoute',
'pouchdb'
])
.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
})
.otherwise({
redirectTo: '/'
});
})
// note the difference here, it is using the object returned by module() and config()
.factory('someservice', function(pouchdb) {
// Do something with pouchdb.
var db = pouchdb.create('testdb');
pouchdb.destroy('testdb');
db.put({_id: 'foo', name: 'bar'});
});
In addition, I was able to adapt this code example to test the DB is working
http://plnkr.co/edit/M2K7no75zonXKcXKF9Sc?p=preview
app.js
'use strict';
angular
.module('myappApp', [
'ngCookies',
'ngResource',
'ngSanitize',
'ngRoute',
'pouchdb'
])
.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
})
.otherwise({
redirectTo: '/'
});
})
.factory('MyModel', function(pouchdb) {
return new pouchdb.create('mydb');
})
.run(function (){
var db = new PouchDB('mydb');
db.info().then(function(info) {
if (info.doc_count < 2) {
db.post({display: 'Hello'});
db.post({display: 'World'});
}
});
});
main.js
'use strict';
angular.module('myappApp')
.controller('MainCtrl', function ($scope, MyModel) {
$scope.awesomeThings = [
'HTML5 Boilerplate',
'AngularJS',
'Karma'
];
MyModel.info().then(function(info) {
$scope.numOfDocs = info.doc_count;
});
$scope.options = {
db: MyModel,
name: 'Visitor'
};
$scope.db = MyModel;
});
main.html
<p>Hello {{options.name}}! There are {{numOfDocs}} docs in your Pouch</p>
<p>Root scope:</p>
<ul>
<li pouch-repeat="item in db" ng-bind="item.display"></li>
</ul>
<p>Child scope:</p>
<ul>
<li pouch-repeat="item in options.db" ng-bind="item.display"></li>
</ul>
Due This Article I try to create an application with AngularJS and RequireJS!
I can load angular library... create module and export it to external files! It's ok!
But the problem is I can't create configuration and controllers for my module both in main application file and external files!
Another issue is I can't load views and controllers in app.js via $routeProvider!!
(Sorry for grammer problems!)
app.js:
require.config({
baseUrl: "/angularjs/js",
paths: {
"angular": "libs/angular.min"
},
shim: {
"angular": {
exports: "angular"
}
}
});
define('app', ['angular'], function(angular){
var app = angular.module('myApp', []);
app.config(function($routeProvider, $locationProvider){
$routeProvider
.when('/', {
controller: 'HomeCtrl'
templateUrl: 'views/home.html'
});
});
return app;
});
require(["app", "controllers/homeController"]);
controllers/homeController.js:
require(["app"], function(app) {
app.controller("HomeCtrl",
function($scope) {
$scope.message = "Hello World!";
}
);
});
index.html:
<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="UTF-8" />
<title>Angular.js</title>
<script type="text/javascript" data-main="js/" src="js/libs/require.js"></script>
<script type="text/javascript" src="js/app.js"></script>
</head>
<body>
<div ng-view></div>
</body>
</html>
views/home.html:
<div ng-controller="HomeCtrl">
<h1>{{messge}}</h1>
</div>
Here is my version of your example. With a few changes it works fine.
It is better to bootstrap AngularJs application manually, when RequireJs.
I separated app.js file in two: main.js - with configuration of RequireJs and app.js - with AngularJs module declaration. Later, this module is used by homeController for declaration of controller. Then, the controller is required in main.js and the application is bootstrapping.
I do the angular and requireJS integration placing NG_DEFER_BOOTSTRAP! flag and have separate files for my app config and routing like in:
require.config({
baseUrl: 'js/',
paths: {
angular: '../lib/bower_components/angular/angular.min',
angularRoute: '../lib/bower_components/angular-route/angular-route.min'
},
shim: {
'angular': {
'exports': 'angular'
},
'angularRoute':{
'deps': ['angular']
}
},
priority: [
'angular'
]
});
//https://docs.angularjs.org/guide/bootstrap
window.name = 'NG_DEFER_BOOTSTRAP!';
require([
'angular',
'app',
'routes'
], function(angular, app, routes) {
'use strict';
var $html = angular.element(document.getElementsByTagName('html')[0]);
angular.element().ready(function() {
angular.resumeBootstrap([app['name']]);
});
});
app.js:
define([
'angular',
'filters',
'services',
'directives',
'controllers',
'animations',
'angularRoute'
], function (angular) {
'use strict';
return angular.module('myapp', [
'ngRoute',
'ngCookies',
'ngAnimate',
'myapp.services',
'myapp.directives',
'myapp.filters',
'myapp.controllers',
'myapp.animations'
]);
});
and routes.js:
define(['angular', 'app'], function(angular, app) {
'use strict';
return app.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/home', {
templateUrl: 'partials/home.html',
controller: 'HomeCtrl'
}).
when('/login', {
templateUrl: 'partials/login.html',
controller: 'LoginCtrl'
}).
otherwise({
redirectTo: '/home'
});
}])
});
hope this helps in your scenario.