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' component 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 completed 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 becomes:
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?
Your 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) {
}]);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With