HTMLとJavaScriptを用いシンプルにサーバーから取得したデータをブラウザ上に表示する

タイトルにあるようなコードを他の方に教える機会がありましたので、Qiitaにも投稿させて頂こうと思います。探せば幾らでもあるような非常に基礎的な内容かとは存じますが、何らか参考になれば幸いです。

## 前提

今回想定するのは以下のようなアプリケーションです。
1. 画面にアクセスした段階で、サーバーからデータを取得し画面に表示する。
2. 画面にある入力欄に値を入力し、送信ボタンを押してサーバー側に新しいデータを保存する。
3. データが保存できたら、再度サーバー側にアクセスし新しいデータ一覧を画面に再描画する。
尚、今回はproductId, productNameという2つのデータを扱うAPIが/api/v1/productというURIで定義されているものとします。

## コード

#### HTML(index.html)

```html

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>Main Page</title>
</head>
<body>
	This is demo application main page.
	<div id="data"></div>
	<div id="form">
		<div id="text">
			productId : <input type="text" id="productId">
			productName : <input type="text" id="productName">
		</div>
		<div id="button">
			<input type="button" value="submit" id="submit">
		</div>
	</div>
</body>
<script type="text/javascript" src="../js/main.js"></script>
</html>

```

#### JavaScript(main.js)

```javascript

var Main = (function() {
	var url = {
		"productUrl" : "/api/v1/product"
	}

	var productModel = {
		productId : 0,
		productName : "",
		set : function() {
			this.productId = document.getElementById("productId").value;
			this.productName = document.getElementById("productName").value;
		}
	}

	var view = {
		render : function(data) {
			document.getElementById("data").textContent = JSON.stringify(data);
		}
	}

	var service = {
		search : function() {
			return fetch(url.productUrl).then(function(response) {
				return response.json();
			});
		},
		add : function(data) {
			return fetch(url.productUrl, {
				method : 'post',
				headers : new Headers({
					"Content-type": "application/json"
				}),
				body : data
			})
		}
	}

	return {
		init : function() {
			service.search().then(function(json) {
				view.render(json);
			});

			var submitDom = document.getElementById("submit");
			submitDom.addEventListener("click", function() {
				productModel.set();
				var data = JSON.stringify(productModel);
				service.add(data).then(function(res) {
					if (res.ok) {
						service.search().then(function(json) {
							view.render(json);
						});
					} else {
						window.alert("error occured");
					}
				})
			});
		}
	}
})();

Main.init();

```

## 補足

#### HTML
入力欄が2つ、送信用のボタンが1つととてもシンプルです。
main.jsはDOMの操作を行うためbodyタグの下で読み込ませています。（headタグなどで読み込ませると、イベントを貼るためのDOMがまだ存在しない）

#### JavaScript
やや長くなっておりますが、各オブジェクトの役割は以下となっています。

・ mainオブジェクト
このファイルの存在する唯一のグローバルオブジェクト。グローバルオブジェクトを無闇に増やさないために、Mainオブジェクトのみ即時関数で生成し他のオブジェクトはprivateにしている。publicなのはinitメソッドのみ。

・ urlオブジェクト
この程度の行数であれば、このように定数をオブジェクトでまとめるメリットはあまり無い。
が、将来的にコードが長くなり、URLが修正されたりしたときなど（例えばv1→v2になった）、URLをコードを直書きにしていると該当部分全てを修正しないといけなくなる。url.productUrl のように関節的に参照していれば定義している箇所のみ修正すれば良い。

・ productModelオブジェクト
サーバー側とやり取りするためのデータを表すオブジェクト。Idはint型、nameはString型で定義されているものと考えそれぞれの初期値をセットしている。

・ viewオブジェクト
データの画面への描画を司るオブジェクト。今回は単に.textContentで値を差し込むのみ。

・ serviceオブジェクト
サーバー側とのやり取り(ajax）を司るオブジェクト。searchメソッド、addメソッド共にfetchの戻り値であるpromiseをreturnしている。

コードの最終行でMain.init()としている通り、Mainオブジェクトが生成された後はじめに呼ばれるのはinitメソッドです。initメソッドはまずサーバーから初期データをロードし画面に描画した後、送信ボタンがクリックされた時の挙動を設定しています。

## 終わりに

近年の傾向を鑑みjQueryは今回はあえて用いないようにしています。また最低限Model, Viewを意識して分けるようにしました。もう少し処理が長くなってくるとViewやModelは別ファイルにするべきかと思いますが、今回は行数も少ないため同じファイルにて記載しています。