I'm testing AngularJs with Play Framework 2.0 (Scala). Play uses Closure to minimize Javascript files.
My file is as follows:
// Define a Module 'todoList' for Angular that will load the views. In this example the views are very simple, it's just to show
// the concept
angular.module('todoList', ['taskDoneFilter', 'todoServices']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/all', {templateUrl: 'assets/angular/all.html', controller: TodoCtrl}).
when('/task/:id', {templateUrl: 'assets/angular/task.html', controller: TaskDetailCtrl}).
otherwise({redirectTo: '/all'});
}]);
// This filter allows us to convert strings. In this case, it adds an extra tick besides a task indicating if it's done or no
angular.module('taskDoneFilter', []).filter('checkmark', function() {
return function(input) {
return input ? '\u2713' : '\u2718';
};
});
// When running tests with Jasmine the jsRoutes object is not defined, which means we need to use a default route for the http call below
// This kind of defeats the purpose of retrieving the routes via Play instead of hardcoding them, as we need a fallback for the tests
// but I decided to leave the code just to see that we have the possibility, in case I find a way to improve this.
var tasksUrl = '/tasks/all';
if(!(typeof jsRoutes === "undefined")) {
tasksUrl = jsRoutes.controllers.Application.tasks().url ;
}
// Definition of a Service, that stores all the REST requests independently from the controllers, facilitating change
angular.module('todoServices', ['ngResource']).
factory('All', function ($resource) {
return $resource(tasksUrl, {}, {
//The data model is loaded via a GET request to the app
query: {method: 'GET', params: {}, isArray: true}
});
})
.factory('Task', function ($resource) {
return $resource('tasks', {}, {
add: {method: 'POST'}
});
});
/**
* This is the controller behind the view, as declared by ng-controller
* All references to methods and data model in the view map to this controller
* @param $scope model data injected into the controller
* @constructor
*/
var TodoCtrl = ['$scope', 'All', 'Task', function($scope, All, Task) {
// We use the service to query for the data
$scope.todos = All.query();
//when submitting the form, this is called. Model in the form is referenced (todoText) and we add the task to
//the data model
$scope.addTodo = function() {
var txt = $scope.todoText;
$scope.todos.push({text: txt, done: false});
Task.save({msg: txt});
$scope.todoText = ''; //clear the input!
};
// calculates the remaining todos, automatically called when the model changes to update the view
// notice the use of 'angular' ponent for functional approach
$scope.remaining = function() {
var count = 0;
angular.forEach($scope.todos, function(todo) {
count += todo.done ? 0 : 1;
});
return count;
};
//another acton triggered by click (in this case on an anchor), which archives pleted tasks
$scope.archive = function() {
var oldTodos = $scope.todos;
$scope.todos = [];
angular.forEach(oldTodos, function(todo) {
if (!todo.done) $scope.todos.push(todo);
});
};
}];
// Task details controller, used in the routes to provide a second view for the application
var TaskDetailCtrl = ['$scope', '$routeParams', function($scope, $routeParams) {
$scope.id = $routeParams.id;
}];
But when minimizing, it bees:
var module$todo={};angular.module("todoList",["taskDoneFilter","todoServices"]).config(["$routeProvider",function($routeProvider){$routeProvider.when("/all",{templateUrl:"assets/angular/all.html",controller:TodoCtrl$$module$todo}).when("/task/:id",{templateUrl:"assets/angular/task.html",controller:TaskDetailCtrl$$module$todo}).otherwise({redirectTo:"/all"})}]);angular.module("taskDoneFilter",[]).filter("checkmark",function(){return function(input){return input?"\u2713":"\u2718"}});
var tasksUrl$$module$todo="/tasks/all";if(!(typeof jsRoutes==="undefined"))tasksUrl$$module$todo=jsRoutes.controllers.Application.tasks().url;angular.module("todoServices",["ngResource"]).factory("All",function($resource){return $resource(tasksUrl$$module$todo,{},{query:{method:"GET",params:{},isArray:true}})}).factory("Task",function($resource){return $resource("tasks",{},{add:{method:"POST"}})});
var TodoCtrl$$module$todo=["$scope","All","Task",function($scope,All,Task){$scope.todos=All.query();$scope.addTodo=function(){var txt=$scope.todoText;$scope.todos.push({text:txt,done:false});Task.save({msg:txt});$scope.todoText=""};$scope.remaining=function(){var count=0;angular.forEach($scope.todos,function(todo){count+=todo.done?0:1});return count};$scope.archive=function(){var oldTodos=$scope.todos;$scope.todos=[];angular.forEach(oldTodos,function(todo){if(!todo.done)$scope.todos.push(todo)})}}];
var TaskDetailCtrl$$module$todo=["$scope","$routeParams",function($scope,$routeParams){$scope.id=$routeParams.id}];
And then it stops working. Notice the:
var module$todo={};
and
var TodoCtrl$$module$todo=
which break the app.
Anyone knows why may this be happening?
I'm testing AngularJs with Play Framework 2.0 (Scala). Play uses Closure to minimize Javascript files.
My file is as follows:
// Define a Module 'todoList' for Angular that will load the views. In this example the views are very simple, it's just to show
// the concept
angular.module('todoList', ['taskDoneFilter', 'todoServices']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/all', {templateUrl: 'assets/angular/all.html', controller: TodoCtrl}).
when('/task/:id', {templateUrl: 'assets/angular/task.html', controller: TaskDetailCtrl}).
otherwise({redirectTo: '/all'});
}]);
// This filter allows us to convert strings. In this case, it adds an extra tick besides a task indicating if it's done or no
angular.module('taskDoneFilter', []).filter('checkmark', function() {
return function(input) {
return input ? '\u2713' : '\u2718';
};
});
// When running tests with Jasmine the jsRoutes object is not defined, which means we need to use a default route for the http call below
// This kind of defeats the purpose of retrieving the routes via Play instead of hardcoding them, as we need a fallback for the tests
// but I decided to leave the code just to see that we have the possibility, in case I find a way to improve this.
var tasksUrl = '/tasks/all';
if(!(typeof jsRoutes === "undefined")) {
tasksUrl = jsRoutes.controllers.Application.tasks().url ;
}
// Definition of a Service, that stores all the REST requests independently from the controllers, facilitating change
angular.module('todoServices', ['ngResource']).
factory('All', function ($resource) {
return $resource(tasksUrl, {}, {
//The data model is loaded via a GET request to the app
query: {method: 'GET', params: {}, isArray: true}
});
})
.factory('Task', function ($resource) {
return $resource('tasks', {}, {
add: {method: 'POST'}
});
});
/**
* This is the controller behind the view, as declared by ng-controller
* All references to methods and data model in the view map to this controller
* @param $scope model data injected into the controller
* @constructor
*/
var TodoCtrl = ['$scope', 'All', 'Task', function($scope, All, Task) {
// We use the service to query for the data
$scope.todos = All.query();
//when submitting the form, this is called. Model in the form is referenced (todoText) and we add the task to
//the data model
$scope.addTodo = function() {
var txt = $scope.todoText;
$scope.todos.push({text: txt, done: false});
Task.save({msg: txt});
$scope.todoText = ''; //clear the input!
};
// calculates the remaining todos, automatically called when the model changes to update the view
// notice the use of 'angular' ponent for functional approach
$scope.remaining = function() {
var count = 0;
angular.forEach($scope.todos, function(todo) {
count += todo.done ? 0 : 1;
});
return count;
};
//another acton triggered by click (in this case on an anchor), which archives pleted tasks
$scope.archive = function() {
var oldTodos = $scope.todos;
$scope.todos = [];
angular.forEach(oldTodos, function(todo) {
if (!todo.done) $scope.todos.push(todo);
});
};
}];
// Task details controller, used in the routes to provide a second view for the application
var TaskDetailCtrl = ['$scope', '$routeParams', function($scope, $routeParams) {
$scope.id = $routeParams.id;
}];
But when minimizing, it bees:
var module$todo={};angular.module("todoList",["taskDoneFilter","todoServices"]).config(["$routeProvider",function($routeProvider){$routeProvider.when("/all",{templateUrl:"assets/angular/all.html",controller:TodoCtrl$$module$todo}).when("/task/:id",{templateUrl:"assets/angular/task.html",controller:TaskDetailCtrl$$module$todo}).otherwise({redirectTo:"/all"})}]);angular.module("taskDoneFilter",[]).filter("checkmark",function(){return function(input){return input?"\u2713":"\u2718"}});
var tasksUrl$$module$todo="/tasks/all";if(!(typeof jsRoutes==="undefined"))tasksUrl$$module$todo=jsRoutes.controllers.Application.tasks().url;angular.module("todoServices",["ngResource"]).factory("All",function($resource){return $resource(tasksUrl$$module$todo,{},{query:{method:"GET",params:{},isArray:true}})}).factory("Task",function($resource){return $resource("tasks",{},{add:{method:"POST"}})});
var TodoCtrl$$module$todo=["$scope","All","Task",function($scope,All,Task){$scope.todos=All.query();$scope.addTodo=function(){var txt=$scope.todoText;$scope.todos.push({text:txt,done:false});Task.save({msg:txt});$scope.todoText=""};$scope.remaining=function(){var count=0;angular.forEach($scope.todos,function(todo){count+=todo.done?0:1});return count};$scope.archive=function(){var oldTodos=$scope.todos;$scope.todos=[];angular.forEach(oldTodos,function(todo){if(!todo.done)$scope.todos.push(todo)})}}];
var TaskDetailCtrl$$module$todo=["$scope","$routeParams",function($scope,$routeParams){$scope.id=$routeParams.id}];
And then it stops working. Notice the:
var module$todo={};
and
var TodoCtrl$$module$todo=
which break the app.
Anyone knows why may this be happening?
Share Improve this question edited Jan 6, 2013 at 17:08 Pere Villega asked Jan 6, 2013 at 17:00 Pere VillegaPere Villega 16.4k5 gold badges65 silver badges100 bronze badges2 Answers
Reset to default 10Your All
& Task
services are not 'minify safe'. You must use the array notation.
angular.module('todoServices', ['ngResource']).
factory('All', ['$resource', function ($resource) {
return $resource(tasksUrl, {}, {
//The data model is loaded via a GET request to the app
query: {method: 'GET', params: {}, isArray: true}
});
}])
.factory('Task', ['$resource', function ($resource) {
return $resource('tasks', {}, {
add: {method: 'POST'}
});
}]);
Also, define your controller with angular.module(...).controller()
:
angular.module(...).controller('TodoCtrl', ['$scope', 'All', 'Task', function($scope, All, Task) {
}]);
... and if you have a larger app, you can find where you aren't using named references by turning on strictDi (option to bootstrap call or ng-strict-di attribute in tag with ng-app attribute).