サイトトップ

Director Flash 書籍 業務内容 プロフィール

HTML5テクニカルノート

Vue.js + ES6入門 06: 項目を調べてデータから削除する


データバインディングは、データにもとづいてページの表示を動的に描き替える仕組みです。今回は、ページのリスト項目を削除します。考えるのは、ユーザーの操作や条件に応じて、項目のデータをどうやって選んで除くかです。

01 ボタンを加える

「Vue.js + ES6入門 05: 項目を数えて表示する」でつくったコード002「Array.prototype.reduce()メソッドで配列を集計する」に手を加えてゆきましょう。アプリケーションに納めた複数のデータがリストとして示され、入力フィールドのテキストは「追加」ボタンで項目に加えられます。また、項目すべてとチェックのついていない数も、それぞれ示されています(図001)。

図001■全項目数と残りの数が示される

図001

チェック済みの項目だけを、まとめて除けるようにしましょう。クリックする<button>要素を、つぎのように加えます(図002)。v-on:click(省略記法@click)ディレクティブから呼び出すメソッド(archive)はつぎの項で定めます。

<body>要素

<div id="app" class="container">

	<p>
		全{{todos.length}}件中残り{{remaining}}件
		<button  @click="archive" class="btn btn-danger btn-sm">断捨離</button>
	</p>

</div>

図002■件数の右にボタンが加わった

図002

02 条件にしたがってデータを除く

ボタンから呼び出されるのは、methodsオプションに加えたつぎのメソッド(archive())です。チェックをつけた項目は、データのプロパティ(done)の値がtrueになります。そこで、データ(todo)の中からチェックのついていない項目だけを取り出した新たな配列で、もとのリスト項目データ(todos)に上書きしました。Array.prototype.filter()メソッドを使ったこの処理は、「Vue.js + ES6入門 05」のコード001「条件に合ったデータを数えて返す」のremaining算出プロパティと同じです。このときは、使うのは配列でなく項目数だったため、あとでArray.prototype.reduce()メソッドで書き直したのでした(同コード002)。けれど、今回はまさに配列がほしい場合です。

<script>要素

const app = new Vue({
	data: {

		todos: [
			{text: 'Vue.jsを学ぶ', done: true},
			{text: 'Vue.jsでアプリケーションをつくる', done: false},
		]
	},
	methods: {

		archive() {
			this.todos = this.todos.filter((todo) => !todo.done);
		}
	},

});

これで、ボタンを押すとチェック済みの項目はデータから除かれ、画面にはチェックされていない項目だけが残ります(図003)。ここまでのHTMLとJavaScriptの記述は、以下のコード001にまとめました。

図003■チェック済みの項目が除かれた

図003

コード001■条件にしたがってデータから項目を除く

<body>要素

<div id="app" class="container">
	<h2>Todo</h2>
	<p>
		全{{todos.length}}件中残り{{remaining}}件
		<button  @click="archive" class="btn btn-danger btn-sm">断捨離</button>
	</p>
	<ul class="list-unstyled">
		<li v-for="todo in todos">
			<label>
				<input type="checkbox" v-model="todo.done">
				<span :class="{'done': todo.done}">{{todo.text}}</span>
			</label>
		</li>
	</ul>
	<p>
		<input type="text" v-model="todoText" placeholder="add new todo here">
		<button @click="addTodo()" class="btn btn-primary btn-sm">追加</button>
	</p>
</div>

<script>要素

const app = new Vue({
	data: {
		todoText: '',
		todos: [
			{text: 'Vue.jsを学ぶ', done: true},
			{text: 'Vue.jsでアプリケーションをつくる', done: false},
		]
	},
	computed: {
		remaining() {
			const count =
				this.todos.reduce((count, todo) =>
					count = (todo.done) ? count : ++count
				, 0);
			return count;
		}
	},
	methods: {
		addTodo() {
			const newTodo = this.todoText.trim();
			this.todoText = '';
			if (!newTodo) {return;}
			this.todos = [
				...this.todos,
				{text: newTodo, done: false}
			];
		},
		archive() {
			this.todos = this.todos.filter((todo) => !todo.done);
		}
	}
});
document.addEventListener('DOMContentLoaded', () =>
	app.$mount('#app')
);

03 項目に削除ボタンを加える

さらに、チェックのあるなしにかかわらず、項目ごとに消せるようにします。そのために、それぞれの項目に<button>要素を、つぎのように加えてください(図002)。@clickディレクティブから呼び出すメソッド(removeTodo())はつぎの項で定めます。注目していただきたいのは、引数に項目のデータ(todo)を渡していることです。そうしないと、メソッドがどの項目を削除すればよいのかわかりません。

<body>要素

<div id="app" class="container">

	<ul class="list-unstyled">
		<li v-for="todo in todos">

			<button @click="removeTodo(todo)" class="btn btn-warning btn-sm">削除</button>
		</li>
	</ul>

</div>

図004■それぞれの項目の右にボタンが加わった

図004

04 ボタンクリックした項目をデータから除く

methodsオプションに加えるのは、ボタンから呼び出されるメソッド(removeTodo())です。クリックした項目のデータは、引数(todo)に渡されます。すると、つぎのようにデータの配列(todos)から、インデックスを調べて(Array.prototype.indexOf())取り除けばよいでしょう(Array.prototype.splice())。

<script>要素

const app = new Vue({

	methods: {

		removeTodo(todo) {
			const todos = this.todos;
			const index = todos.indexOf(todo);
			todos.splice(index, 1);
		},
	},

});

今回は、もとのリスト項目データ(todos)を書き替えてしまってよいので、このコードでまったく問題ありません。けれど、条件にあった要素の新たな配列をつくるArray.prototype.filter()メソッドの方が、端的でしょう。つぎにまとめたコード002は、こちらの処理を用いました。これで、項目右のボタンを押すとチェック済みかどうかにかかわらず、データから除かれて画面から消えます。コードを試すためのサンプル001も併せて掲げます。

コード002■項目を調べてデータから削除する

<body>要素

<div id="app" class="container">
	<h2>Todo</h2>
	<p>
		全{{todos.length}}件中残り{{remaining}}件
		<button  @click="archive" class="btn btn-danger btn-sm">断捨離</button>
	</p>
	<ul class="list-unstyled">
		<li v-for="todo in todos">
			<label>
				<input type="checkbox" v-model="todo.done">
				<span :class="{'done': todo.done}">{{todo.text}}</span>
			</label>
			<button @click="removeTodo(todo)" class="btn btn-warning btn-sm">削除</button>
		</li>
	</ul>
	<p>
		<input type="text" v-model="todoText" placeholder="add new todo here">
		<button @click="addTodo" class="btn btn-primary btn-sm">追加</button>
	</p>
</div>

<script>要素

const app = new Vue({
	data: {
		todoText: '',
		todos: [
			{text: 'Vue.jsを学ぶ', done: true},
			{text: 'Vue.jsでアプリケーションをつくる', done: false},
		]
	},
	computed: {
		remaining() {
			const count =
				this.todos.reduce((count, todo) =>
					count = (todo.done) ? count : ++count
				, 0);
			return count;
		}
	},
	methods: {
		addTodo() {
			const newTodo = this.todoText.trim();
			this.todoText = '';
			if (!newTodo) {return;}
			this.todos = [
				...this.todos,
				{text: newTodo, done: false}
			];
		},
		removeTodo(todo) {
			this.todos = this.todos.filter((_todo) => _todo !== todo);
		},
		archive() {
			this.todos = this.todos.filter((todo) => !todo.done);
		}
	}
});
document.addEventListener('DOMContentLoaded', () =>
	app.$mount('#app')
);

サンプル001■Vue.js + ES6: Removing bound data according to conditions

See the Pen Vue.js + ES6: Removing bound data according to conditions by Fumio Nonaka (@FumioNonaka) on CodePen.

Vue.js + ES6


作成者: 野中文雄
作成日: 2019年6月8日 FN1702009「Vue.js入門 06: 項目を調べてデータから削除する」とFN1702010「Vue.js入門 07: データを項目ごとに削除する」を全面改訂。


Copyright © 2001-2019 Fumio Nonaka.  All rights reserved.