11
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SvelteAdvent Calendar 2020

Day 17

[Svelte] 孫コンポーネントの入力値をbindするには?

Last updated at Posted at 2020-12-17

はじめに

Svelte初心者向けの記事です。
コードと動作確認は「こちらのREPLでできます。

基本

TutorialのBinding / Text inputs にも書いてありますが、Svelteでは要素に対してbindを付けることで<script>タグに書いた変数と双方向バインドしてくれます。

App.svelte
<script>
	let name = 'world';
</script>

<input bind:value={name}>

<h1>Hello {name}!</h1>

動作確認
ezgif.com-gif-maker (2).gif

子コンポーネントの入力値をbindするには?

ここで、子コンポーネントとしてAppInput.svelteを作成します。

AppInput.svelte(子)
<script>
	// exportで宣言するとコンポーネントのpropsになる
	export let value;
</script>

<input bind:value>

<input bind:value><input bind:value={value}>と同じです。

すると、App.svelte(親)からの呼び出し方はこうなります。

App.svelte(親)
<script>
+	import AppInput from './AppInput.svelte';
	let name = 'world';
</script>


- <input bind:value={name}>
+ <AppInput bind:value={name} />

<h1>Hello {name}!</h1>

ポイントは、親も子コンポーネントのどちらにもbind:を付けてあげる必要があります。

孫コンポーネントの入力値をbindするには?

先程のAppInput.svelteを基底コンポーネントとしたとき、1つのコンポーネントの中に、複数のAppInput.svelteが存在することもあるでしょう。
例えば、以下のようなログイン画面が挙げられます。
ezgif.com-gif-maker (3).gif

このログイン画面のコンポーネント構成は以下の通りです。
image.png

孫コンポーネント

AppInput.svelte(孫)の実装をもう少し改良してみます。

AppInput.svelte(孫)
<script>
-	export let value;
+	export let value = '';
+	export let type = 'text';
+	export let name = '';
+	export let placeholder = '';
+	const props = {
+		type,
+		name,
+		placeholder,
+	};
</script>


- <input bind:value={value}>
+ <input
+	bind:value
+	{...props}
+ />

###注意点(input要素にtypeを設定するには?)
input要素に直接typeを設定すると以下のエラーが発生するので、props変数経由でセットしてください。

'type' attribute cannot be dynamic if input uses two-way binding

子コンポーネント

FormInput.svelte(子)の実装は、ラベル+入力項目としています。ただ、親から渡された属性値を孫に渡しているだけです。**ここでもbind:valuevalue値を連動させる必要があります。

FormInput.svelte(子)
<script>
	import AppLabel from './AppLabel.svelte';
	import AppInput from './AppInput.svelte';

	export let type;
	export let name;
	export let title;
	export let value;
	export let placeholder;
</script>

<AppLabel name='{name}' title='{title}' />
<AppInput
	type='{type}'
	name='{name}'
	placeholder='{placeholder}'
	bind:value
/>

親コンポーネント

ログイン用のコンポーネントとして、emailpasswordの入力項目が必要なため、子コンポーネントであるFormInputを2つ参照しています。

Login.svelte
<script>
	import FormInput from './FormInput.svelte';
	import AppButton from './AppButton.svelte';

	let email;
	let password;

	const login = () => {
		console.log(`${email} | ${password}`);
	};
</script>

<div>
	<FormInput
		type='email'
		name='email'
		title='email'
		bind:value='{email}'
		placeholder='メールアドレスを入力してください'
	/>
	<FormInput
		type='password'
		name='password'
		title='パスワード'
		bind:value='{password}'
		placeholder='パスワードを入力してください'
	/>
</div>
<AppButton on:click='{login}'>ログイン</AppButton>

###注意点(bind:valueって何?)
今までbind:valueとして定義してきましたが、これはbind:value='{value}'の省略形です。そのため、それぞれbind:value='{email}'bind:value='{password}'のようにbindする対象を指定する必要があります。

もちろんbind:valuevalueexportした変数名なので、FormInput.svelte

FormInput.svelte
	export let inputValue;

と宣言したなら、bind:inputValue='{email}'となります。

11
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?