我从您的问题(以及您的 SO 标签)中看到您想在 AngularJS 中创建一个类似 Rails 的控制器。由于两个框架(Rails 和 AngularJS)共享相似的 MVC 原理,这实际上很容易实现。
这两个框架都允许您指示不同的路由使用相同的控制器。
在 Rails 中,您常用的 index/show/new/edit/destroy 方法(操作)是开箱即用的(带有脚手架)。这些默认操作映射到不同的、完善的路由和 HTTP 方法。
Rails 中的 CRUD/列出路线
现在,在 AngularJS 应用程序(或所有 SPA)中,您只需要这些路由的一个子集,因为客户端路由只理解 GET 请求:
AngularJS 中的 CRU/列表路由
AngularJS 本身不提供会为您生成所有 CRUD 路由的脚手架机制。但尽管如此,它为您提供了至少两种不同的方式来使用单个控制器连接您的 CRUD/List 路由。
选项 1(使用$location.path()
)
使用 location.path() 方法,您可以PhotosCtrl
根据位置路径构建不同的操作。
路线:
app.config(
[
'$routeProvider',
function ($routeProvider) {
$routeProvider
.when('/photos', {
templateUrl: 'photos/index.html',
controller: 'PhotosCtrl'
})
.when('/photos/new', {
templateUrl: 'photos/new.html',
controller: 'PhotosCtrl'
})
.when('/photos/:id', {
templateUrl: 'photos/show.html',
controller: 'PhotosCtrl'
})
.when('/photos/:id/edit', {
templateUrl: 'photos/edit.html',
controller: 'PhotosCtrl'
});
}
]
);
控制器:
app.controller('PhotosCtrl', [
'$scope',
'Photos', // --> Photos $resource with custom '$remove' instance method
'$location',
'$routeParams',
function($scope, Photos, $location, $routeParams){
if($location.path() === '/photos'){
// logic for listing photos
$scope.photos = Photos.query();
}
if($location.path() === '/photos/new'){
// logic for creating a new photo
$scope.photo = new Photos();
}
if(/\/photos\/\d*/.test($location.path())){ // e.g. /photos/44
// logic for displaying a specific photo
$scope.photo = Photos.get({id: $routeParams.id});
}
if(/\/photos\/\d*\/edit/.test($location.path())){ // e.g. /photos/44/edit
// logic for editing a specific photo
$scope.photo = Photos.get({id: $routeParams.id});
}
// Method shared between 'show' and 'edit' actions
$scope.remove = function(){
$scope.photo.$remove();
}
// Method shared between 'new' and 'edit' actions
$scope.save = function(){
$scope.photo.$save();
}
}
]);
这四个ifs
让控制器看起来有点乱,但是当用一个替换 4 个不同的控制器时,很少有条件是不可避免的。
选项 2(使用解析属性)
此选项resolve
使用路由配置对象的属性为不同的路由生成不同的“动作标识符”。
路线:
app.config(
[
'$routeProvider',
function ($routeProvider) {
$routeProvider
.when('/photos', {
templateUrl: 'photos/index.html',
controller: 'PhotosCtrl',
resolve: {
action: function(){return 'list';}
}
})
.when('/photos/new', {
templateUrl: 'photos/new.html',
controller: 'PhotosCtrl',
resolve: {
action: function(){return 'new';}
}
})
.when('/photos/:id', {
templateUrl: 'photos/show.html',
controller: 'PhotosCtrl',
resolve: {
action: function(){return 'show';}
}
})
.when('/photos/:id/edit', {
templateUrl: 'photos/edit.html',
controller: 'PhotosCtrl',
resolve: {
action: function(){return 'edit';}
}
});
}
]
);
控制器:
app.controller('PhotosCtrl', [
'$scope',
'Photos',
'$routeParams',
'action'
function($scope, Photos, $routeParams, action){
if(action === 'list'){
// logic for listing photos
$scope.photos = Photos.query();
}
if(action === 'new'){
// logic for creating a new photo
$scope.photo = new Photos();
}
if(action === 'show')
// logic fordisplaying a specfiic photo
$scope.photo = Photos.get({id: $routeParams.id});
}
if(action === 'edit')
// logic for editing a specfic photo
$scope.photo = Photos.get({id: $routeParams.id});
}
// Method shared between 'show' and 'edit' actions
$scope.remove = function(){
$scope.photo.$remove();
}
// Method shared between 'new' and 'edit' actions
$scope.save = function(){
$scope.photo.$save();
}
}
]);
这两种方法都需要在控制器中使用一些条件,但第二种方法至少更清晰易读,因为确切的操作在路由机制内部解决,这会从繁忙的控制器中移除一些逻辑。
当然,在任何实际应用程序中,您可能会在控制器内部定义更多方法,在这种情况下,您的控制器可能会变得非常不可读。这些示例使用一个简单的 $resource 实例 ( Phones
),它依赖于一个简单的 RESTfull 后端 API(Rails?)。但是,当您的视图逻辑变得复杂时,您可能需要使用 Angular 服务/工厂来抽象控制器中的一些代码。