現在、アプリ管理者用の CRUD を作成しています。RESTfull API で AngularJS を使用しています。単純なモデルを正常に保存できます。しかし、多対多の関係がある場合、更新/作成フォームの設定に関しては少し迷っています。この試みを紹介するために、Plunker を作成しました: http://plnkr.co/edit/okeNuYBJ5f33gtu6WBoW
編集:
Jasonが提案したように、ドロップダウンの代わりにチェックボックスを使用するようになりました:
http://plnkr.co/edit/okeNuYBJ5f33gtu6WBoW
しかし、私の問題 #3 はまだ修正されていません。これらの更新/作成された関係を保存するにはどうすればよいですか?
だから私はロールモデルと多対多の関係を持つユーザーモデルを持っています。モデルとその関係を表示/一覧表示できます。ユーザーを編集するときに、すべてのロールをロードして、UI が選択するロールのドロップダウンを作成できるようにします。関係があるのと同じ数のドロップダウンが必要です。そのため、ドロップダウンを repeat="userRole in user.role" にネストしました。
更新を行う場合
最初の問題: ユーザーが多くのロールを持っている場合、ドロップダウンはできるだけ多く表示されますが、それぞれに選択されたロールは最初の関係です。
2 番目の問題: 読み込まれたユーザーに新しいロールを追加するボタンがあります。保存すると、新しくアタッチされた役割の痕跡が表示されないため、正しく作成したかどうかはわかりません。
3 番目の問題: 保存するときに、ロールからの接続が失われます。ユーザーのみが更新されます。私のフォームは間違っていますが、どこに問題がありますか?
作成するとき
役割を新しいユーザーにリンクできません。「新しい役割の追加」をクリックすると、役割リストの最初の役割がユーザーにプッシュされます。しかし、ユーザーはまだ作成されていません。だから私はエラーが発生します。またしても私のフォームは間違っています。エラーは何ですか?新しいユーザーを保存するときに、関連する役割も POST するにはどうすればよいですか?
Plunker が機能しない場合のコードを次に示します。
index.html
<!DOCTYPE html>
<html lang="en" xmlns:ng="http://angularjs.org" data-ng-app="CRUD">
<head>
<meta charset="UTF-8" />
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.1.1/css/bootstrap.no-icons.min.css" />
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/font-awesome/2.0/css/font-awesome.css" />
</head>
<body>
<div class="span6" ng-view></div>
<script src="http://code.angularjs.org/1.1.0/angular.min.js"></script>
<script src="http://code.angularjs.org/1.1.0/angular-resource.js"></script>
<script src="/crud.js"></script>
</body>
</html>
crud.js AngularJS 固有のコード
var users = [
{'id':1,'name':'User 1', 'role':[{'id':1,'name':'Role 1'},{'id':2,'name':'Role 2'}]},
{'id':2,'name':'User 2', 'role':[{'id':2,'name':'Role 2'}]},
{'id':3,'name':'User 3', 'role':[{'id':1,'name':'Role 1'}]},
{'id':4,'name':'User 4', 'role':[{'id':3,'name':'Role 3'},{'id':2,'name':'Role 2'}]}
];
var roles = [
{'id':1,'name':'Role 1'},
{'id':2,'name':'Role 2'},
{'id':3,'name':'Role 3'}
];
/* Route */
angular.module('CRUD', []).
config(['$routeProvider', function ($routeProvider) {
$routeProvider.
when('/create', {templateUrl: 'create.html',controller: ctrlCreate}).
when('/read', {templateUrl: 'read.html',controller: ctrlRead}).
when('/update/:userId', {templateUrl: 'update.html', controller: ctrlUpdate}).
otherwise({redirectTo: 'read'});
}]);
/* Controller CREATE */
function ctrlCreate($scope, $http, $location) {
// dirty hack to find the user to update (in real life it would be loaded via REST)
$scope.user = null;
$scope.roles = roles;
$scope.save = function() {
// dirty hack to change the user (in real life it would be trigger a POST request to the server with updated model)
users.push($scope.user);
//if a scope digestion is already going on then it will get picked up and you won't have to call the $scope.$apply() method
if(!$scope.$$phase) { //this is used to prevent an overlap of scope digestion
$scope.$apply(); //this will kickstart angular to recognize the change
}
$location.path('/');
};
$scope.addRole = function(){
$scope.user.role.push(roles[0]);
};
}
ctrlCreate.$inject = ['$scope','$http','$location'];
/* Controller READ */
function ctrlRead($scope, $http, $location) {
// dirty hack to find the user to update (in real life it would be loaded via REST)
$scope.users = users;
$scope.roles = roles;
}
ctrlRead.$inject = ['$scope','$http','$location'];
/* Controller UPDATE */
function ctrlUpdate($scope, $http, $location, $routeParams) {
$scope.user = null;
$scope.roles = roles;
var id=$routeParams.userId;
// dirty hack to find the user to update (in real life it would be loaded via REST)
for (var i = 0; i < users.length; i++) {
if (users[i].id==id) {
$scope.user=users[i];
console.debug($scope.user.role);
}
}
$scope.save = function() {
// dirty hack to change the user (in real life it would be trigger a PUT request to the server with updated model)
for (var i = 0; i < users.length; i++) {
if (users[i].id==id) {
users[i] = $scope.user;
}
}
//if a scope digestion is already going on then it will get picked up and you won't have to call the $scope.$apply() method
if(!$scope.$$phase) { //this is used to prevent an overlap of scope digestion
$scope.$apply(); //this will kickstart angular to recognize the change
}
$location.path('/');
};
$scope.addRole = function(){
$scope.user.role.push(roles);
console.debug($scope.user.role);
};
}
ctrlUpdate.$inject = ['$scope','$http','$location', '$routeParams'];
今私のテンプレート:
create.html
<form>
<div class="control-group">
<label class="control-label">Name</label>
<input type="text" ng-model="user.name" placeholder="Enter a name here">
</div>
<div ng-repeat="userRole in user.role">
<div class="control-group">
<label class="control-label">Role</label>
<select ng-selected="userRole.id">
<option ng-repeat="role in roles" value="{{role.id}}">{{role.name}}</option>
</select>
</div>
</div>
<button ng-click="addRole()">Attach another role</button>
<br />
<br />
<input type="submit" value="Submit" ng-click="save()" class="btn btn-primary">
<a href="#/" class="btn">Cancel</a>
</form>
read.html
<br />
<table class="table table-bordered table-striped table-centred table-condensed table-hover">
<thead>
<tr>
<th>User Name</th>
<th>Role Name</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="user in users">
<td>{{user.name}}</td>
<td>
<span ng-repeat="role in user.role">{{role.name}}</span>
</td>
<td>
<a title="edit" href="#/update/{{user.id}}"><i class="icon-edit"></i></a>
</td>
</tr>
</tbody>
</table>
<br />
<a href="#/create" class="btn btn-primary"><i class="icon-plus"></i> Create a new user</a>
update.html
<form>
<div class="control-group">
<label class="control-label">Name</label>
<input type="text" ng-model="user.name" placeholder="Enter a name here">
</div>
<div ng-repeat="userRole in user.role">
<div class="control-group">
<label class="control-label">Role</label>
<select ng-selected="userRole.id">
<option ng-repeat="role in roles" value="{{role.id}}">{{role.name}}</option>
</select>
</div>
</div>
<button ng-click="addRole()">Attach another role</button>
<br />
<br />
<input type="submit" value="Submit" ng-click="save()" class="btn btn-primary">
<a href="#/" class="btn">Cancel</a>
</form>
不適切なコーディングや不適切なアーキテクチャが見られた場合は、アドバイスをお願いします (たとえば、新しい役割を追加する場合などに何らかのディレクティブを実行できると思います)。これが十分に明確であることを願っています。ありがとう!