サーバーから受信したデータをもとに画面を更新するようにしたところ、最初のチェックに対してはToDo項目が完了済みに移動したが、2個目からは移動しなくなってしまった。
これは、change()イベントを拾う処理が画面読み込み完了時(load)のみに行われているため。
新しく生成した input[name=”items”] のセレクタで指定した要素にはイベントを拾う処理が登録されていないために動作しない。
この対策を実施する。
まずはload時の処理をfunctionに分割する。
<!DOCTYPE html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ToDoアプリ</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
init();
})
function init() {
$('input[name="items"]').change(function(){
console.log($(this).parent());
$('#done').append($(this).parent());
$.post(
'done',
'id=' + $(this).val(),
function(data) {
console.log(data);
$('#todo form').children().remove();
$('#done').children().remove();
for (var i = 0; i < data.length; i++) {
var div = $('<div>');
div.attr('id', 'check' + data[i].id);
var cb = $('<input>')
.attr('type', 'checkbox')
.attr('name', 'items')
.attr('value', data[i].id);
div.append(cb).append(data[i].item);
if (data[i].done == null) {
$('#todo form').append(div);
} else {
cb.attr('checked', 'checked');
$('#done').append(div);
}
}
});
});
}
</script>
</head>
<body>
<h1>ToDo項目</h1>
<form method="post" action="input">
<input type="text" name="item">
<input type="submit" value="登録">
</form>
<div id="todo">
<c:if test="${list != null}">
<form method="post" action="check">
<c:forEach var="t" items="${list}">
<c:if test="${t.done == null}">
<div id="check${t.id}">
<input type="checkbox" name="items" value="${t.id}" />${t.item}
</div>
</c:if>
</c:forEach>
</form>
</c:if>
</div>
<hr />
<h3>完了済み</h3>
<div id="done">
<c:if test="${list != null}">
<c:forEach var="t" items="${list}">
<c:if test="${t.done != null}">
<div id="check${t.id}">
<input type="checkbox" name="items" value="${t.id}" checked="checked" />${t.item}
</div>
</c:if>
</c:forEach>
</c:if>
</div>
</body>
</html>
この変更ではいままでどおりの動作となる。
さらに、サーバーからデータを受信して、新規に要素を生成して画面上に追加した処理のあとに init() を呼ぶようにすることで、チェックボックスのイベントに対しての処理を行うようにする。
<!DOCTYPE html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ToDoアプリ</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
init();
})
function init() {
$('input[name="items"]').change(function(){
console.log($(this).parent());
$('#done').append($(this).parent());
$.post(
'done',
'id=' + $(this).val(),
function(data) {
console.log(data);
$('#todo form').children().remove();
$('#done').children().remove();
for (var i = 0; i < data.length; i++) {
var div = $('<div>');
div.attr('id', 'check' + data[i].id);
var cb = $('<input>')
.attr('type', 'checkbox')
.attr('name', 'items')
.attr('value', data[i].id);
div.append(cb).append(data[i].item);
if (data[i].done == null) {
$('#todo form').append(div);
} else {
cb.attr('checked', 'checked');
$('#done').append(div);
}
}
init();
});
});
}
</script>
</head>
<body>
<h1>ToDo項目</h1>
<form method="post" action="input">
<input type="text" name="item">
<input type="submit" value="登録">
</form>
<div id="todo">
<c:if test="${list != null}">
<form method="post" action="check">
<c:forEach var="t" items="${list}">
<c:if test="${t.done == null}">
<div id="check${t.id}">
<input type="checkbox" name="items" value="${t.id}" />${t.item}
</div>
</c:if>
</c:forEach>
</form>
</c:if>
</div>
<hr />
<h3>完了済み</h3>
<div id="done">
<c:if test="${list != null}">
<c:forEach var="t" items="${list}">
<c:if test="${t.done != null}">
<div id="check${t.id}">
<input type="checkbox" name="items" value="${t.id}" checked="checked" />${t.item}
</div>
</c:if>
</c:forEach>
</c:if>
</div>
</body>
</html>
チェックボックスのチェックを外された時は、ToDo項目を完了済みから未完了に移動させるようにする。
サーバー側では、URL /redo を用意する。処理の内容は、done()とほぼ同じで、ToDoエンティティのcreatedの値を現在時刻にして、doneの値をnullに戻すだけの違い。
@RequestMapping(value = "/redo", method = RequestMethod.POST)
@ResponseBody
@ResponseStatus(value = HttpStatus.OK)
public List<ToDo> redo(@RequestParam(value = "id") String id, Model model) {
ToDoDao<ToDo> dao = new ToDoDaoImpl();
ToDo todo = dao.findById(Long.parseLong(id));
todo.setCreated(new Date());
todo.setDone(null);
dao.update(todo);
List<ToDo> list = dao.getAll();
return list;
}
ブラウザ側では、完了済みにあるチェックボックスのチェックが外されたときは、redo に POST 送信するように、JavaScriptコードを書き換えればよい。
<!DOCTYPE html>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>ToDoアプリ</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
init();
})
function init() {
$('input[name="items"]').change(function(){
console.log($(this).prop('checked'));
var url;
if ($(this).prop('checked')) {
url = 'done';
} else {
url = 'redo';
}
$.post(
url,
'id=' + $(this).val(),
function(data) {
console.log(data);
$('#todo form').children().remove();
$('#done').children().remove();
for (var i = 0; i < data.length; i++) {
var div = $('<div>');
div.attr('id', 'check' + data[i].id);
var cb = $('<input>')
.attr('type', 'checkbox')
.attr('name', 'items')
.attr('value', data[i].id);
div.append(cb).append(data[i].item);
if (data[i].done == null) {
$('#todo form').append(div);
} else {
cb.attr('checked', 'checked');
$('#done').append(div);
}
}
init();
});
});
}
</script>
</head>
<body>
<h1>ToDo項目</h1>
<form method="post" action="input">
<input type="text" name="item">
<input type="submit" value="登録">
</form>
<div id="todo">
<c:if test="${list != null}">
<form method="post" action="check">
<c:forEach var="t" items="${list}">
<c:if test="${t.done == null}">
<div id="check${t.id}">
<input type="checkbox" name="items" value="${t.id}" />${t.item}
</div>
</c:if>
</c:forEach>
</form>
</c:if>
</div>
<hr />
<h3>完了済み</h3>
<div id="done">
<c:if test="${list != null}">
<c:forEach var="t" items="${list}">
<c:if test="${t.done != null}">
<div id="check${t.id}">
<input type="checkbox" name="items" value="${t.id}" checked="checked" />${t.item}
</div>
</c:if>
</c:forEach>
</c:if>
</div>
</body>
</html>
Gitによるバージョン管理
Eclipseでプロジェクトを右クリックし、[チーム]-[プロジェクトの共用]を選択する。
リポジトリタイプは「Git」を選択し「次へ」をクリックする。
リポジトリの「作成」をクリックし、リポジトリディレクトリに「C:\Users\name\git」が指定されている。
「完了」ボタンが押せない場合は、フォルダ名を適当に変更して「完了」ボタンが有効になるようにし、「完了」をクリックする。
「完了」すると、プロジェクト名の右側に「NO-HEAD」の表示が出る。
プロジェクトを右クリックし、[チーム]-[コミット]を選択すると、画面の下にコミット対象となるファイルの一覧が表示される。余計なファイルがたくさん含まれているので、これを除外する設定を行う。
リポジトリ内にあるプロジェクトのフォルダ内に「.gitignore」ファイルを作成する。
エクスプローラでは新規ファイルでテキストファイル「gitignore.txt」を作成する。
コマンドプロンプトを起動してファイル名を変更する。
> ren gitignore.txt .gitignore
.gitignore ファイル内に、除外するファイルやフォルダ名を記載する。
/target
.settings/
.classpath
.project
/pleiades45
.gitignore ファイルを保存したら、Eclipseでプロジェクトを右クリックし「リフレッシュ」を選択する。
プロジェクトを右クリックし[チーム]-[コミット]を選択する。
コミット対象のファイル一覧に余計なファイルが含まれていないことを確認したら、コミットメッセージに変更理由(今回は最初なので「新規作成」でもよい)などを記載して「コミット」をクリックする。
コミットが成功したら、プロジェクト名の右側が「master」に変化する。