Svelte journey | Props, Template Directives, Events
Tags: svelte, javascript, tutorial, frontend
Published: 2023-12-22 19:33:52



Welcome,
this is the second part of our amazing Svelte journey. Previously, we’ve learned about the [basics, template and reactivity](https://dev.to/chillyhill/svelte-journey-part-1-38pa). Today, we'll delve into **Props, Template Directives, and Events**. So, let’s start.

## Props

### ⚠️  `export` keyword is not regular JS `export`

`export` marks that a variable is an external, input property.

```jsx
<script>
	export let foo; // 'export' means input prop
	export let marko = 'Polo'; //  input prop with default value
</script>
```

### {…spread} props

Pretty same as in React:

```jsx
<PackageInfo
	name={pkg.name}
	speed={pkg.speed}
	version={pkg.version}
	website={pkg.website}
/>
```

```jsx
<PackageInfo {...pkg} />
```

### **$$props  — last resort stuff** 🚩

Is needed for **reference all props** (including also properties, that **were not mentioned as  inputs (**`export let <prop name>`) **for the component**).

- Feels like `(…props: any[])` or JS function’s `arguments`;
- `$$restProps` allows to do the same but only for props, that **were not mentioned as inputs**;
- Not recommended, difficult for Svelte to optimise.

## Template Directives

```jsx
// Conditional rendering
{#if count > 10}
	<p>{count} is greater than 10</p>
{:else if count < 5}
	<p>{count} is less than 5</p>
{:else}
	<p>{count} is between 5 and 10</p>
{/if}
// Iterables (any generic iterables) rendering
{#each colors as color, i (color)} // ", i" is optional; (*) is key, also optional
	<span>{color}, idx: {i}</span>
{/each}

```

### `Key` for lists rendering

- similar to other libs/frameworks, optimises DOM updates;
- any object can be `key`, but string or number is safer. So keep it safe.

```jsx
// Key usage samples
{#each things as thing, i (thing.id)}
	<Thing name={thing.name + " - " + i}  />
{/each}
{#each things as thing, i (i)}
	<Thing name={thing.name + " - " + i}  />
{/each}

```

### `await` blocks for async operations 🍭

- Kinda `async` pipe from Angular or `useQuery` from [tanstack's library](https://tanstack.com/query/v4/docs/react/reference/useQuery)
- Only the most recent promise is considered — new value comes into variable and cancels previous pending state if some.

```jsx
// Basic async stuff
{#await promise}
	<p>...waiting</p>
{:then number}
	<p>The number is {number}</p>
{:catch error}
	<p style="color: red">{error.message}</p>
{/await}

// if you're sure there are no rejects
{#await promise then number}
	<p>The number is {number}</p>
{/await}

```

## Events

```jsx
<script>
	let m = { x: 0, y: 0 };

	function handleMove(event) {
		m.x = event.clientX;
		m.y = event.clientY;
	}
</script>

<div
	on:pointermove={handleMove}  // Handler fn.
	on:click={(e) => {           // Inline handler
		console.log(m, e.target);
	}}
>
	The pointer is at {m.x} x {m.y}
</div>

```

### `Modifiers` for event handlers 🍰

Pipelike handy notation to apply modifiers:

```jsx
<button on:click|once={() => alert('clicked')}>
	Click me
</button>
<button on:click|once|self|capture={() => alert('you can chain them!')}>
	Click me
</button>

```

**Available modifiers:**

- `preventDefault`;
- `stopPropagation`;
- `passive` — about scrolling. Svelte handles it automatically;
- `nonpassive` — explicitly set passive: false`capture`;
- `once`;
- `self` — only trigger handler if event.target is the element itself;
- `trusted` — only trigger handler if event.isTrusted is true, meaning it is a action performed by human (click) rather than by code.

### Component events
You need to:

- have a name for an event;
- dispatch this event via special dispatcher service, that is provided by svelte;
- assign to events and handle them.

Here is a simple example:

```jsx
// Inner.svelte --------------------------------------------------------------
<script>
    import { createEventDispatcher } from 'svelte'; // the service

    const dispatch = createEventDispatcher(); // we created dispatcher

    function doSomething() { 
        dispatch('somethingHappened', { // dispatch 'somethingHappened' event
            action: 'You did it!'
        });
    }
</script>

<button on:click={doSomething}> // click will trigger event dispatch
    Do it.
</button>
// Outer.svelte --------------------------------------------------------------
...
<Inner on:somethingHappened={handleEvent} /> // listen to an event
...
```

And this example is more broad, it depicts how you can forward dispatches and how to handle not only component events, but also DOM events:
```jsx
// App.svelte ------------------------------------------------------------
<script>
	import Outer from './Outer.svelte';
	import CustomButton from './CustomButton.svelte';

	function handleMessage(event) {
		alert(event.detail.action);
	}

	function handleClick(event) {
		alert("Polo!");
	}

</script>
<Outer on:somethingHappened={handleMessage} />

<CustomButton on:click={handleClick} />
// Outer.svelte ------------------------------------------------------------
<script>
	import Inner from './Inner.svelte';
	import { createEventDispatcher } from 'svelte';

	const dispatch = createEventDispatcher();

	function forward(e) {
		dispatch('somethingHappened', e.detail);
	}
</script>

<Inner on:somethingHappened={forward} />
// Inner.svelte ------------------------------------------------------------
<script>
	import { createEventDispatcher } from 'svelte';

	const dispatch = createEventDispatcher();

	function doSomething() {
		dispatch('somethingHappened', {
			action: 'And something happened!'
		});
	}
</script>

<button on:click={doSomething}>
	Time has come
</button>
// CustomButton.svelte -------------------------------------------------------
<script>
	import { createEventDispatcher } from 'svelte';
	const dispatch = createEventDispatcher();

	function forwardClick(e) {
		dispatch('click', e)
	}
</script>
<button on:click={forwardClick}>
	Marko
</button>

<style>
	button {
			background: navajowhite;
			padding: 4px 8px;
	}
</style>

```

- `createEventDispatcher` must be called **at the initialisation;**
- component events don't ***bubble — you need to forward them;***
- **DOM event forwarding** — **t**he same as component’s events.

## Amazing REPL, Amazing CLI

The code snippets quickly outgrew the tutorial's IDE, prompting me to seek alternatives. I turned to the Svelte REPL, an online environment that seemed perfect and even offered PWA installation. However, my intention was to experiment without registration, which unfortunately wasn't allowed.

Undeterred, I chose to download it locally using `npm create svelte@latest my-app`, and the experience was remarkably convenient 🏅. However, my initial excitement dwindled when npm install raised concerns about broken dependencies. While forcing it was an option, opting for stability with a non-beta version proved to be the solution. It serves as a valuable reminder that only reliable components should make their way into production.

In the end, everything is running smoothly.

Take care, go Svelte!

## Resources

- [Svelte Tutorial](https://learn.svelte.dev/)