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