nkjmkzk.net

powered by Kazuki Nakajima

AngularJSではじめるHTML5開発 – Part8 モーダルダイアログによる新規レコード作成フォーム

Part7の続きです。

今回は新規ゲスト作成フォームを実装していきます。Part6で登場したモーダルダイアログ、そしてPart7で登場したPromise/Deferredパターンを駆使していきます。

new_guest_form

まずは今回開発する部分をデモでみてみましょう。

デモ

それでは実装へ。

 

新規ゲストフォームのモーダルダイアログを作成する

まずモーダルダイアログとなるHTMLマークアップを作成しておきましょう。

	<!-- Modal for newGuestForm -->
	<script type="text/ng-template" id="T_newGuestForm">
		<div class="modal-header">
			<button type="button" class="close" ng-click="$dismiss()">&times;</button>
		    <h3>新規ゲスト</h3>
		</div>
		<div class="modal-body">
			<form role="form">
				<div class="form-group">
					<label>ゲスト名</label>
					<input ng-model="newGuest.Name" type="text" class="form-control" placeholder="ゲスト名" />
				</div>
				<div class="form-group">
					<label>Email</label>
					<input ng-model="newGuest.email__c" type="email" class="form-control" placeholder="Email" />
				</div>
			</form>
		</div>
		<div class="modal-footer">
			<button type="button" class="btn btn-success" ng-click="createGuest()">作成</button>
		</div>
	</script><!-- Modal for newGuestForm-->

ほとんどのマークアップはPart6で紹介したものなので容易に理解できると思います。

各フォームがバインドするデータモデルは既存のゲストと区別するためにnewGuestとなっています。

 

モーダルダイアログを開くopenNewGuestForm()を作成する

		$scope.openNewGuestForm = function(){
			$scope.newGuest = {};
			$modal.open({
				templateUrl: "T_newGuestForm",
				scope: $scope
			});
		}

モーダルダイアログを開く部分はもうご存知の通りです。重要なのはその手前でデータモデル$scope.newGuestを初期化しているところです。

これはscopeの階層構造上必要となる処理です。

子scopeは親scopeのプロパティを参照できますが、親scopeは子scopeのプロパティにアクセスできません。

今回、openNewGuestForm()は親scopeとなり、モーダルダイアログはその子scopeとして作成されます。したがって、newGuestを親scopeで定義しておくとモーダルダイアログではそれを参照する形になりますが、親scopeでnewGuestを定義していなかった場合は、モーダルダイアログのng-modelの指定によって子scopeでnewGuestが作成されることになります。

後続の処理で親scopeがnewGuestへのアクセスを必要としますので今回は親scope側でデータモデルを作成しています。

 

新規ゲスト作成処理の流れを記述するcreateGuest()を作成する

		$scope.createGuest = function(){
			$modal.open({
				templateUrl: "T_inProgress",
				backdrop: "static",
				scope: $scope
			});

			$scope.remotingProgress = 33;
			$scope.remotingStatus = "ゲストを作成しています...";

			$scope.deferredCreateGuest()
			.then(
				function(){
					$scope.remotingProgress = 66;
					$scope.remotingStatus = "ゲストリストをリフレッシュしています...";
					return $scope.deferredGetGuests();
				},
				function(result){
					return $q.reject(result);
				}
			)
			.then(
				function(guests){
					$scope.guests = guests;
					$scope.newGuest = {};
					$scope.remotingProgress = 100;
					$scope.remotingStatus = "作成が完了しました。";
				},
				function(result){
					console.log(result);
				}
			);
		}

ほとんどはupdateGuest()と同じ流れですね。

一点、下記の$scope.newGuestを再初期化している部分に注目してみてください。

					$scope.newGuest = {};

今回の処理ではゲスト作成処理が完了しても新規ゲストフォームはまだ表示されたままになっています。これはユースケースにもよると思いますが、連続的にデータを作成していきたい場合にはこのような仕様が適していると思います。

その際、そのままだとユーザーが入力した値がそのまま残ってしまいます。したがって一旦$scope.newGuestを初期化してフォームをクリアしているわけです。

 

deferredCreateGuest()を作成する

		$scope.deferredCreateGuest = function(){
			var deferred = $q.defer();

			$scope.force.create(
				"guest__c",
				$scope.newGuest,
				function(result){
					deferred.resolve();
				},
				function(result){
					deferred.reject(result);
				}
			);
			return deferred.promise;
		}

この関数はPart7で学んだPromise/Deferredに対応させています。ここではRemoteTKのcreate()メソッドでデータベースにアクセスし、レコードを作成しています。

create()の第一引数はオブジェクト名、第二引数はデータです。データには$scope.newGuestをそのまま渡してあげればOKです。

 

新規ボタンを設置する

最後にサイドバーの右上に「新規」ボタンを設置しておきましょう。

コード:新規ボタン

				<div class="panel panel-default">
					<div class="panel-heading">
						ゲスト
						<button type="submit" class="btn btn-xs btn-default pull-right" ng-click="openNewGuestForm()"><span class="glyphicon glyphicon-plus"></span>&nbsp; 新規</button>
					</div>
					<div class="list-group">
						<a class="list-group-item" href="#" ng-click="getGuest(guest.Id)" ng-repeat="guest in guests">{{guest.Name}}</a>
					</div>
				</div>

いわずもがな、クリックするとopenNewGuestForm()を実行してモーダルダイアログを呼び出します。

さて、随分と基本機能ができあがってきてアプリらしくなってきました。
次回はこのサイトにレスポンシブデザインを適用し、モバイルデバイスに対応させていきます。

例によって最後に現時点でのindexファイルの全ソースを掲載しておきます。

<apex:page showHeader="false" standardStyleSheets="false" applyBodyTag="false" applyHtmlTag="false" docType="html-5.0" >
  
<html ng-app="ngbootcamp">
<head>
	<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.0/css/bootstrap.min.css"></link>
	<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
	<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.0/js/bootstrap.min.js"></script>
	<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.10/angular.min.js"></script>
	<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.10.0/ui-bootstrap-tpls.min.js"></script>
	<c:RemoteTK />
	<script>
	var ngbootcamp = angular.module('ngbootcamp', ['ui.bootstrap']);

	ngbootcamp.controller('guestCtl', function($scope, $modal, $q){
		$scope.openNewGuestForm = function(){
			$scope.newGuest = {};
			$modal.open({
				templateUrl: "T_newGuestForm",
				scope: $scope
			});
		}

		$scope.createGuest = function(){
			$modal.open({
				templateUrl: "T_inProgress",
				backdrop: "static",
				scope: $scope
			});

			$scope.remotingProgress = 33;
			$scope.remotingStatus = "ゲストを作成しています...";

			$scope.deferredCreateGuest()
			.then(
				function(){
					$scope.remotingProgress = 66;
					$scope.remotingStatus = "ゲストリストをリフレッシュしています...";
					return $scope.deferredGetGuests();
				},
				function(result){
					return $q.reject(result);
				}
			)
			.then(
				function(guests){
					$scope.guests = guests;
					$scope.newGuest = {};
					$scope.remotingProgress = 100;
					$scope.remotingStatus = "作成が完了しました。";
				},
				function(result){
					console.log(result);
				}
			);
		}

		$scope.updateGuest = function(){
			$modal.open({
				templateUrl: "T_inProgress",
				backdrop: "static",
				scope: $scope
			});

			$scope.remotingProgress = 33;
			$scope.remotingStatus = "データを更新しています...";

			$scope.deferredUpdateGuest()
			.then(
			function(){
				$scope.remotingProgress = 66;
				$scope.remotingStatus = "ゲストリストをリフレッシュしています...";
				return $scope.deferredGetGuests();
			},
			function(result){
				return $q.reject(result);
			})
			.then(
			function(guests){
				$scope.guests = guests;
				$scope.remotingProgress = 100;
				$scope.remotingStatus = "更新が完了しました。";
			},
			function(result){
				console.log(result);
			});
		}

		$scope.deferredCreateGuest = function(){
			var deferred = $q.defer();

			$scope.force.create(
				"guest__c",
				$scope.newGuest,
				function(result){
					deferred.resolve();
				},
				function(result){
					deferred.reject(result);
				}
			);
			return deferred.promise;
		}

		$scope.deferredUpdateGuest = function(){
			var deferred = $q.defer();
			var guest = angular.copy($scope.guest);
			delete guest.attributes;

			$scope.force.update(
				"guest__c",
				$scope.guest.Id,
				guest,
				function(result){
					deferred.resolve();
				},
				function(result){
					deferred.reject(result);
				}
			);
			return deferred.promise;
		}

		$scope.getGuest = function(recordId){
			$scope.force.retrieve(
				"guest__c",
				recordId,
				"Id,Name,email__c",
				function(result){
					$scope.guest = result;
					$scope.$apply();
				},
					function(result){
					console.log(result);
				}
			);
		}

		$scope.deferredGetGuests = function(){
			var deferred = $q.defer();
			var soql = "select Id, Name, CreatedDate from guest__c";
			$scope.force.query(
				soql,
				function(result){
					deferred.resolve(result.records);
				},
				function(result){
					deferred.reject(result);
				}
			);
			return deferred.promise;	
		}

		$scope.force = new remotetk.Client();
		$scope.deferredGetGuests()
		.then(
			function(guests){
				$scope.guests = guests;
			},
			function(result){
				console.log(result);
			}
		);
	});
	</script>
</head>
<body ng-controller="guestCtl">
	<div class="container" style="margin-top:20px;">
		<div class="row">
			<div class="col-md-4">
				<div class="panel panel-default">
					<div class="panel-heading">
						ゲスト
						<button type="submit" class="btn btn-xs btn-default pull-right" ng-click="openNewGuestForm()"><span class="glyphicon glyphicon-plus"></span>&nbsp; 新規</button>
					</div>
					<div class="list-group">
						<a class="list-group-item" href="#" ng-click="getGuest(guest.Id)" ng-repeat="guest in guests">{{guest.Name}}</a>
					</div>
				</div>
			</div>
			<div class="col-md-8">
				<h1>{{guest.Name}}</h1>
				<form role="form">
					<div class="form-group">
						<label>ゲスト名</label>
						<input ng-model="guest.Name" type="text" class="form-control" placeholder="ゲスト名" />
					</div>
					<div class="form-group">
						<label>Email</label>
						<input ng-model="guest.email__c" type="email" class="form-control" placeholder="Email" />
					</div>
					<div class="form-group">
						<button class="btn btn-success" ng-click="updateGuest()">更新</button>
					</div>
				</form>
			</div>
		</div>
	</div>

	<!-- Modal for newGuestForm -->
	<script type="text/ng-template" id="T_newGuestForm">
		<div class="modal-header">
			<button type="button" class="close" ng-click="$dismiss()">&times;</button>
		    <h3>新規ゲスト</h3>
		</div>
		<div class="modal-body">
			<form role="form">
				<div class="form-group">
					<label>ゲスト名</label>
					<input ng-model="newGuest.Name" type="text" class="form-control" placeholder="ゲスト名" />
				</div>
				<div class="form-group">
					<label>Email</label>
					<input ng-model="newGuest.email__c" type="email" class="form-control" placeholder="Email" />
				</div>
			</form>
		</div>
		<div class="modal-footer">
			<button type="button" class="btn btn-success" ng-click="createGuest()">作成</button>
		</div>
	</script><!-- Modal for newGuestForm-->

	<!-- Modal for inProgress -->
	<script type="text/ng-template" id="T_inProgress">
		<div class="modal-header">
		    <h3>
		    	<span ng-show="remotingProgress < 100">処理中</span>
		    	<span ng-show="remotingProgress == 100">完了</span>
	    	</h3>
		</div>
		<div class="modal-body">
			<div>{{remotingStatus}}</div>
		    <progressbar ng-class="(remotingProgress < 100) ? 'progress-striped active' : 'progress'" value="remotingProgress" type="success"></progressbar>
		</div>
		<div class="modal-footer" ng-show="remotingProgress == 100">
			<button type="button" class="btn btn-success" ng-click="$close()">閉じる</button>
		</div>
	</script><!-- Modal for inProgress-->

</body>
</html>
  
</apex:page>

 

関連情報

without comments

Written by 中嶋 一樹

2月 16th, 2014 at 3:43 pm

Leave a Reply