mirror of https://github.com/sveltejs/svelte
parent
991e46422b
commit
5563b3781e
@ -0,0 +1,9 @@
|
|||||||
|
<script>
|
||||||
|
let name = 'world';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input value={name}>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<h1>Hello {name}!</h1>
|
@ -0,0 +1,9 @@
|
|||||||
|
<script>
|
||||||
|
let name = 'world';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input bind:value={name}>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<h1>Hello {name}!</h1>
|
@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
title: Text inputs
|
||||||
|
---
|
||||||
|
|
||||||
|
As a general rule, data flow in Svelte is *top down* — a parent component can set props on a child component, and a component can set attributes on an element, but not the other way around.
|
||||||
|
|
||||||
|
Sometimes it's useful to break that rule. Take the case of the `<input>` element in this component — we *could* add an `on:input` event handler that set the value of `name` to `event.target.value`, but it's a bit... boilerplatey. It gets even worse with other kinds of form element, as we'll see.
|
||||||
|
|
||||||
|
Instead, we can use the `bind:value` directive:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<input bind:value={name}>
|
||||||
|
```
|
||||||
|
|
||||||
|
This means that not only will changes to the value of `name` update the input value, but changes to the input value will update `name`.
|
@ -0,0 +1,16 @@
|
|||||||
|
<script>
|
||||||
|
let a = 1;
|
||||||
|
let b = 2;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=number value={a} min=0 max=10>
|
||||||
|
<input type=range value={a} min=0 max=10>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=number value={b} min=0 max=10>
|
||||||
|
<input type=range value={b} min=0 max=10>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<p>{a} + {b} = {a + b}</p>
|
@ -0,0 +1,16 @@
|
|||||||
|
<script>
|
||||||
|
let a = 1;
|
||||||
|
let b = 2;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=number bind:value={a} min=0 max=10>
|
||||||
|
<input type=range bind:value={a} min=0 max=10>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=number bind:value={b} min=0 max=10>
|
||||||
|
<input type=range bind:value={b} min=0 max=10>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<p>{a} + {b} = {a + b}</p>
|
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
title: Numeric inputs
|
||||||
|
---
|
||||||
|
|
||||||
|
In the DOM, everything is a string. That's unhelpful when you're dealing with numeric inputs — `type="number"` and `type="range"` — as it means you have to remember to coerce `input.value` before using it.
|
||||||
|
|
||||||
|
With `bind:value`, Svelte takes care of it for you:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<input type=number bind:value={a} min=0 max=10>
|
||||||
|
<input type=range bind:value={a} min=0 max=10>
|
||||||
|
```
|
@ -0,0 +1,18 @@
|
|||||||
|
<script>
|
||||||
|
let yes = false;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=checkbox checked={yes}>
|
||||||
|
Yes! Send me regular email spam
|
||||||
|
</label>
|
||||||
|
|
||||||
|
{#if yes}
|
||||||
|
<p>Thank you. We will bombard your inbox and sell your personal details.</p>
|
||||||
|
{:else}
|
||||||
|
<p>You must opt in to continue. If you're not paying, you're the product.</p>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<button disabled={!yes}>
|
||||||
|
Subscribe
|
||||||
|
</button>
|
@ -0,0 +1,18 @@
|
|||||||
|
<script>
|
||||||
|
let yes = false;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=checkbox bind:checked={yes}>
|
||||||
|
Yes! Send me regular email spam
|
||||||
|
</label>
|
||||||
|
|
||||||
|
{#if yes}
|
||||||
|
<p>Thank you. We will bombard your inbox and sell your personal details.</p>
|
||||||
|
{:else}
|
||||||
|
<p>You must opt in to continue. If you're not paying, you're the product.</p>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<button disabled={!yes}>
|
||||||
|
Subscribe
|
||||||
|
</button>
|
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
title: Checkbox inputs
|
||||||
|
---
|
||||||
|
|
||||||
|
Checkboxes are used for toggling between states. Instead of binding to `input.value`, we bind to `input.checked`:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<input type=checkbox bind:checked={yes}>
|
||||||
|
```
|
@ -0,0 +1,54 @@
|
|||||||
|
<script>
|
||||||
|
let scoops = 1;
|
||||||
|
let flavours = ['Mint choc chip'];
|
||||||
|
|
||||||
|
function join(flavours) {
|
||||||
|
if (flavours.length === 1) return flavours[0];
|
||||||
|
return `${flavours.slice(0, -1).join(', ')} and ${flavours[flavours.length - 1]}`;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h2>Size</h2>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=radio group={scoops} value={1}>
|
||||||
|
One scoop
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=radio group={scoops} value={2}>
|
||||||
|
Two scoops
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=radio group={scoops} value={3}>
|
||||||
|
Three scoops
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<h2>Flavours</h2>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=checkbox group={flavours} value="Cookies and cream">
|
||||||
|
Cookies and cream
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=checkbox group={flavours} value="Mint choc chip">
|
||||||
|
Mint choc chip
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=checkbox group={flavours} value="Raspberry ripple">
|
||||||
|
Raspberry ripple
|
||||||
|
</label>
|
||||||
|
|
||||||
|
{#if flavours.length === 0}
|
||||||
|
<p>Please select at least one flavour</p>
|
||||||
|
{:else if flavours.length > scoops}
|
||||||
|
<p>Can't order more flavours than scoops!</p>
|
||||||
|
{:else}
|
||||||
|
<p>
|
||||||
|
You ordered {scoops} {scoops === 1 ? 'scoop' : 'scoops'}
|
||||||
|
of {join(flavours)}
|
||||||
|
</p>
|
||||||
|
{/if}
|
@ -0,0 +1,52 @@
|
|||||||
|
<script>
|
||||||
|
let scoops = 1;
|
||||||
|
let flavours = ['Mint choc chip'];
|
||||||
|
|
||||||
|
let menu = [
|
||||||
|
'Cookies and cream',
|
||||||
|
'Mint choc chip',
|
||||||
|
'Raspberry ripple'
|
||||||
|
];
|
||||||
|
|
||||||
|
function join(flavours) {
|
||||||
|
if (flavours.length === 1) return flavours[0];
|
||||||
|
return `${flavours.slice(0, -1).join(', ')} and ${flavours[flavours.length - 1]}`;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<h2>Size</h2>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=radio bind:group={scoops} value={1}>
|
||||||
|
One scoop
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=radio bind:group={scoops} value={2}>
|
||||||
|
Two scoops
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type=radio bind:group={scoops} value={3}>
|
||||||
|
Three scoops
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<h2>Flavours</h2>
|
||||||
|
|
||||||
|
{#each menu as flavour}
|
||||||
|
<label>
|
||||||
|
<input type=checkbox bind:group={flavours} value={flavour}>
|
||||||
|
{flavour}
|
||||||
|
</label>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
{#if flavours.length === 0}
|
||||||
|
<p>Please select at least one flavour</p>
|
||||||
|
{:else if flavours.length > scoops}
|
||||||
|
<p>Can't order more flavours than scoops!</p>
|
||||||
|
{:else}
|
||||||
|
<p>
|
||||||
|
You ordered {scoops} {scoops === 1 ? 'scoop' : 'scoops'}
|
||||||
|
of {join(flavours)}
|
||||||
|
</p>
|
||||||
|
{/if}
|
@ -0,0 +1,36 @@
|
|||||||
|
---
|
||||||
|
title: Group inputs
|
||||||
|
---
|
||||||
|
|
||||||
|
If you have multiple inputs relating to the same value, you can use `bind:group` along with the `value` attribute. Radio inputs in the same group are mutually exclusive; checkbox inputs in the same group form an array of selected values.
|
||||||
|
|
||||||
|
Add `bind:group` to each input:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<input type=radio bind:group={scoops} value={1}>
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, we could make the code simpler by moving the checkbox inputs into an `each` block. First, add a `menu` variable to the `<script>` block...
|
||||||
|
|
||||||
|
```js
|
||||||
|
let menu = [
|
||||||
|
'Cookies and cream',
|
||||||
|
'Mint choc chip',
|
||||||
|
'Raspberry ripple'
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
...then replace the second section:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<h2>Flavours</h2>
|
||||||
|
|
||||||
|
{#each menu as flavour}
|
||||||
|
<label>
|
||||||
|
<input type=checkbox bind:group={flavours} value={flavour}>
|
||||||
|
{flavour}
|
||||||
|
</label>
|
||||||
|
{/each}
|
||||||
|
```
|
||||||
|
|
||||||
|
It's now easy to expand our ice cream menu in new and exciting directions.
|
@ -0,0 +1,14 @@
|
|||||||
|
<script>
|
||||||
|
import marked from 'marked';
|
||||||
|
|
||||||
|
let markdown = `Some words are *italic*, some are **bold**`;
|
||||||
|
$: rendered = marked(markdown);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
textarea { width: 100%; height: 200px; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<textarea value={markdown}></textarea>
|
||||||
|
|
||||||
|
{@html rendered}
|
@ -0,0 +1,14 @@
|
|||||||
|
<script>
|
||||||
|
import marked from 'marked';
|
||||||
|
|
||||||
|
let markdown = `Some words are *italic*, some are **bold**`;
|
||||||
|
$: rendered = marked(markdown);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
textarea { width: 100%; height: 200px; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<textarea bind:value={markdown}></textarea>
|
||||||
|
|
||||||
|
{@html rendered}
|
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
title: Textarea inputs
|
||||||
|
---
|
||||||
|
|
||||||
|
The `<textarea>` element behaves similarly to a text input in Svelte — use `bind:value`:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<textarea bind:value={markdown}></textarea
|
||||||
|
```
|
@ -0,0 +1,39 @@
|
|||||||
|
<script>
|
||||||
|
let questions = [
|
||||||
|
{ id: 1, text: `Where did you go to school?` },
|
||||||
|
{ id: 2, text: `What is your mother's name?` },
|
||||||
|
{ id: 3, text: `What is another personal fact that an attacker could easily find with Google?` }
|
||||||
|
];
|
||||||
|
|
||||||
|
let selected;
|
||||||
|
|
||||||
|
let answer = '';
|
||||||
|
|
||||||
|
function handleSubmit() {
|
||||||
|
alert(`answered question ${selected.id} (${selected.text}) with "${answer}"`);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
input { display: block; width: 500px; max-width: 100%; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<h2>Insecurity questions</h2>
|
||||||
|
|
||||||
|
<form on:submit|preventDefault={handleSubmit}>
|
||||||
|
<select value={selected} on:change="{() => answer = ''}">
|
||||||
|
{#each questions as question}
|
||||||
|
<option value={question}>
|
||||||
|
{question.text}
|
||||||
|
</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<input bind:value={answer}>
|
||||||
|
|
||||||
|
<button disabled={!answer} type=submit>
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p>selected question {selected ? selected.id : '[waiting...]'}</p>
|
@ -0,0 +1,39 @@
|
|||||||
|
<script>
|
||||||
|
let questions = [
|
||||||
|
{ id: 1, text: `Where did you go to school?` },
|
||||||
|
{ id: 2, text: `What is your mother's name?` },
|
||||||
|
{ id: 3, text: `What is another personal fact that an attacker could easily find with Google?` }
|
||||||
|
];
|
||||||
|
|
||||||
|
let selected;
|
||||||
|
|
||||||
|
let answer = '';
|
||||||
|
|
||||||
|
function handleSubmit() {
|
||||||
|
alert(`answered question ${selected.id} (${selected.text}) with "${answer}"`);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
input { display: block; width: 500px; max-width: 100%; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<h2>Insecurity questions</h2>
|
||||||
|
|
||||||
|
<form on:submit|preventDefault={handleSubmit}>
|
||||||
|
<select bind:value={selected} on:change="{() => answer = ''}">
|
||||||
|
{#each questions as question}
|
||||||
|
<option value={question}>
|
||||||
|
{question.text}
|
||||||
|
</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<input bind:value={answer}>
|
||||||
|
|
||||||
|
<button disabled={!answer} type=submit>
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p>selected question {selected ? selected.id : '[waiting...]'}</p>
|
@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
title: Select bindings
|
||||||
|
---
|
||||||
|
|
||||||
|
We can also use `bind:value` with `<select>` elements. Update line 24:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<select bind:value={selected} on:change="{() => answer = ''}">
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that the `<option>` values are objects rather than strings. Svelte doesn't mind.
|
||||||
|
|
||||||
|
> Because we haven't set an initial value of `selected`, the binding will set it to the default value (the first in the list) automatically. Be careful though — until the binding is initialised, `selected` remains undefined, so we can't blindly reference e.g. `selected.id` in the template.
|
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"title": "Bindings"
|
||||||
|
}
|
Loading…
Reference in new issue