more chapters

pull/2143/head
Richard Harris 7 years ago
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"
}

@ -67,9 +67,10 @@ Another one should cover how to set up an editor for syntax highlighting.
## Bindings ## Bindings
* [ ] Form bindings (input, textarea, select) * [ ] Form bindings (input, textarea, select, multiple select)
* [ ] Dimensions * [ ] Dimensions
* [ ] `this` * [ ] `this`
* [ ] shorthand
## Stores ## Stores

Loading…
Cancel
Save