Categories
JavaScript Svelte

Passing Arguments into Svelte Actions

Svelte is an up and coming front end framework for developing front end web apps.

It’s simple to use and lets us create results fast.

In this article, we’ll look at how to pass parameters into actions.

Adding Parameters

Actions can take arguments. This means that the action will be called alongside the elements it belongs to.

For instance, we can create an app where we display a message when we clicked and held a button for a specified amount of time that we can change with a slider.

To make this, we write the following code:

longpress.js

export const longpress = (node, duration) => {  
  let timer; 
  const handleMousedown = () => {  
    timer = setTimeout(() => {  
      node.dispatchEvent(new CustomEvent("longpress"));  
    }, duration);  
  }; 

  const handleMouseup = () => {  
    clearTimeout(timer);  
  }; 

  node.addEventListener("mousedown", handleMousedown);  
  node.addEventListener("mouseup", handleMouseup); return {  
    destroy() {  
      node.removeEventListener("mousedown", handleMousedown);  
      node.removeEventListener("mouseup", handleMouseup);  
    },  
    update(newDuration) {  
      duration = newDuration;  
    }  
  };  
};

App.svelte :

<script>  
  import { longpress } from "./longpress.js";
  let pressed = false;  
  let duration = 2000;  
</script>

<label>  
  <input type=range bind:value={duration} max={2000} step={100}>  
  {duration}ms  
</label>

<button use:longpress={duration}  
  on:longpress="{() => pressed = true}"  
  on:mouseenter="{() => pressed = false}"  
>
  press and hold
</button>

{#if pressed}  
  <p>You pressed for {duration}ms</p>  
{/if}

In the code above, we created a longpress action that takes a duration as an argument.

We have the update method in the object we return to update the duration when it’s passed in.

Then when we click the mouse, the mousedown event is emitted, and then the handleMousedown is called.

We dispatch the custom longpress event after the specified duration via setTimeout .

Then when the mouse button is released, handleMouseup is called, and then clearTimeout is called.

Then in App.svelte , we have the button that we long press to see the message. We have the slider to adjust how long the long-press last until we see the message.

This works because we listened to the longpress event emitted by the button, which is attached to the longpress action with the use:longpress directive.

When we first hover over the button, then mouseenter event is emitted and pressed is set to false .

When the longpress event is emitted from longprss , which is emitted, when we hold the button for long enough, then pressed is set to true .

Then the message is displayed when pressed is true .

If we need to pass in multiple arguments, we pass in one object with multiple properties like:

use:longpress={{duration, foo}}

Conclusion

We can pass in a single argument to action. This lets us adjust our actions in the way that we want.

The update function is required to update the value when the argument is updated.

Categories
JavaScript Svelte

Adding Lifecycle Hooks to Elements with Svelte Actions

Svelte is an up and coming front end framework for developing front end web apps.

It’s simple to use and lets us create results fast.

In this article, we’ll look at how to use actions to add lifecycle hooks to elements of our choice.

Actions

Actions are element level lifecycle functions. They’re useful for that needs to listen to element events like tooltips, and interfacing with third-party libraries.

For example, we can use it to make a box that bounces when we drag it as follows:

pannable.js :

export const pannable = node => {  
  let x;  
  let y; const handleMousedown = event => {  
    x = event.clientX;  
    y = event.clientY; node.dispatchEvent(  
      new CustomEvent("panstart", {  
        detail: { x, y }  
      })  
    ); 
    window.addEventListener("mousemove", handleMousemove);  
    window.addEventListener("mouseup", handleMouseup);  
  }; 

  const handleMousemove = event => {  
    const dx = event.clientX - x;  
    const dy = event.clientY - y;  
    x = event.clientX;  
    y = event.clientY; node.dispatchEvent(  
      new CustomEvent("panmove", {  
        detail: { x, y, dx, dy }  
      })  
    );  
  }; 

  const handleMouseup = event => {  
    x = event.clientX;  
    y = event.clientY; node.dispatchEvent(  
      new CustomEvent("panend", {  
        detail: { x, y }  
      })  
    ); 
    window.removeEventListener("mousemove", handleMousemove);  
    window.removeEventListener("mouseup", handleMouseup);  
  }; 

  node.addEventListener("mousedown", handleMousedown); return {  
    destroy() {  
      node.removeEventListener("mousedown", handleMousedown);  
    }  
  };  
};

App.svelte :

<script>  
  import { spring } from "svelte/motion";  
  import { pannable } from "./pannable.js"; 

  const coords = spring(  
    { x: 0, y: 0 },  
    {  
      stiffness: 0.2,  
      damping: 0.4  
    }  
  ); 

  const handlePanStart = () => {  
    coords.stiffness = coords.damping = 1;  
  }; 

  const handlePanMove = event => {  
    coords.update($coords => ({  
      x: $coords.x + event.detail.dx,  
      y: $coords.y + event.detail.dy  
    }));  
  }; 

  const handlePanEnd = event => {  
    coords.stiffness = 0.2;  
    coords.damping = 0.4;  
    coords.set({ x: 0, y: 0 });  
  };  
</script>

<style>  
  .box {  
    position: absolute;  
    width: 100px;  
    height: 100px;  
    border-radius: 4px;  
    background-color: green;  
    cursor: move;  
  }  
</style>

<div class="box"  
  use:pannable  
  on:panstart={handlePanStart}  
  on:panmove={handlePanMove}  
  on:panend={handlePanEnd}  
  style="transform:  
    translate({$coords.x}px,{$coords.y}px)  
    rotate({$coords.x * 0.2}deg)"  
>
</div>

In the code above, we created a div that listens to the pannable ‘s events. We use the pannable action with the use:pannable directive.

The pannable function has all the custom events that whatever it applies to emits.

In the handleMousedown listener of the pannable function, we have the node , which is the DOM node the action is attached to, and we set x and y with the mouse position. Then we call dispatchEvent to emit a custom event, which is panstart to send the x and y coordinates to our parent compone.t

In the handleMousemove function, we handle mouse moves by changing the position of the box, which is node , by using x and y to translate the box. Then we dispatch a custom panmove event to the parent.

When the mouse stops moving, the handleMouseup event handler is called, which sets x and y to the coordinates of the mouse. Then we dispatch the panned event with the x and y coordinates.

When the div box is destroyed, we called node.removeListener to remove the mousedown listener when the box is being destroyed.

In App.svelte , we use the x and y coordinates sent from pannable to update the coordinates of the box.

When also added a bounce effect with the spring transition that’s built into Svelte. coords is the animation effect that’s returned from spring . It has the x and y coordinates for the box, which we’ll update the location of the box as the mouse moves.

When the panstart , panmove , and panned events are triggered, we set the coordinates of the box.

Because mousemove triggers the emission of the panstart event we set the stiffness and the damping of the animation.

mousemove triggers the panmove event to be emitted, which changes the coordinates of the box.

Then when we stop moving the mouse and release the button, the panend event is triggered so that handlePanEnd is called to change the box’s coordinates back to (0, 0).

The style attribute of the div is dynamic and depends on coords , so the box will move as coords changes. We also rotate the box with the angle as a function of coords , so we’ll also see rotation.

Therefore, when we drag the box and then release the mouse button, we’ll see a bounce effect.

Conclusion

In Svelte, actions are functions that emit custom events. We can attach the action to an element and then listen to those custom events to manipulate the elements as we wish.

Categories
JavaScript Svelte

Adding Reactivity to Our Svelte App

Svelte is an up and coming front end framework for developing front end web apps.

It’s simple to use and lets us create results fast.

In this article, we’ll look at how to run code reactivity when variable values change in a Svelte app.

Reactivity

We can add reactivity to our app with the $ sign. To do this, we write something like:

<script>  
  let count = 0;  
  $: doubleCount = count * 2; 
  const handleClick = () => {  
    count += 1;  
  };  
</script>

<main>  
  <button on:click={handleClick}>  
    Increment  
  </button>  
  <p>{count} {doubleCount}</p>  
</main>

Then code:

$: doubleCount = count * 2;

is reactive. This means that this will run with count is updated.

The $: is a label.

Therefore, when we click the button, both count and doubleCount will be updated with the latest values.

We can also put a block after the $: as follows:

<script>  
  let count = 0;  
  let doubleCount = 0;  
  $: {  
    doubleCount = count * 2;  
    console.log(count);  
  } 

  const handleClick = () => {  
    count += 1;  
  };  
</script>

<main>  
  <button on:click={handleClick}>  
    Increment  
  </button>  
  <p>{count} {doubleCount}</p>  
</main>

In the code above, we have the following:

$: {  
  doubleCount = count * 2;  
  console.log(count);  
}

We run code to update doubleCount and log count ‘s value in the same block.

Reactivity is triggered by assignment, so array methods like push and splice won’t automatically cause updates.

Therefore, we have to make the assignment event if the method changes the array in-place.

For instance, we can write the following code:

App.svelte :

<script>  
  let nums = [];  
  let count = 0; 
  const handleClick = () => {  
    nums = [...nums, count];  
    count++;  
  };  
</script>

<main>  
  <button on:click={handleClick}>  
    Add Number  
  </button>  
  <p>{nums.join(', ')}</p>  
</main>

In the code above, we have the handleClick function, which put the nums ‘s existing values in a new array with the spread operator, then we put the current count as the last element of the array instead of calling push to append count to the nums array.

Then we increment the count .

We should then get a list of numbers separated by commas as we click the Add Number button.

Assignment to properties of arrays and objects work the same way as an assignment to values themselves.

For instance, the following code:

App.svelte :

<script>  
  let nums = [];  
  let count = 0; 
  const handleClick = () => {  
    nums[nums.length] = count;  
    count++;  
  };  
</script>

<main>  
  <button on:click={handleClick}>  
    Add Number  
  </button>  
  <p>{nums.join(', ')}</p>  
</main>

works the same way as the code in the previous example.

The variable must appear on the left-hand side of the assignment operator for the assignment to be reactive.

Therefore, if we want to update a nested property, then we have to do something like the following:

App.svelte :

<script>  
  let obj = { foo: { bar: "bar" } }; const handleClick = () => {  
    obj.foo.bar = obj.foo.bar === "foo" ? "bar" : "foo";  
  };  
</script><main>  
  <button on:click={handleClick}>  
    Toggle  
  </button>  
  <p>{obj.foo.bar}</p>  
</main>

In the code above, if we click the Toggle button, we’ll assign the obj.foo.bar property to 'foo' or 'bar' depending on the value of obj.foo.bar .

Therefore, when we click the Toggle button, it should switch between foo and bar .

Conclusion

We can make a reactive property that’s derived from another property by writing: $: before the expression.

$: can also be used with a block.

To update a reactive value, we always have to reassign the value to the existing variable. As long as the variable we’re updating appears on the left side of the assignment expression, it’ll update.

Categories
JavaScript Svelte

Getting Started with Svelte Framework for Front End Development

Svelte is an up and coming front end framework for developing front end web apps.

It’s simple to use and lets us create results fast.

In this article, we’ll look at how to create our first app with Svelte.

Creating the Project

To write our first app, we can create our Svelte project by downloading thw svelte-app.zip from https://svelte.dev/blog/the-easiest-way-to-get-started.

Then we extract it and run npm install to install the packages.

Alternatively, we can run:

npx degit sveltejs/template my-svelte-project  
cd my-svelte-project  
npm install  
npm run dev

to create our Svelte project. We can substitute my-svelte-project with the name of our choice.

Then we go to http://localhost:5000/.

In index.js , we should have:

import App from "./App.svelte";const app = new App({  
  target: document.body  
});export default app;

as the entry point for our app.

It’ll display our app’s content in the body tag of our app.

Writing our First App

Now that we have our app running, we can start writing some code. For instance,

We can write the following:

App.svelte :

<script>  
  let name = "Jane";  
</script><main>  
  Hello {name}  
</main>

to create our first app. It has a name variable, which is set to 'Jane' , and we referenced it in our template.

Therefore, we should get Hello Jane displayed on the screen.

The code in the script tag is referenced in the main markup.

We can add styling to the style tag. For instance, we can write:

App.svelte :

<script>  
  let name = "Jane";  
</script><style>  
  p {  
    font-weight: bold;  
  }  
</style><main>  
  <p>Hello {name}</p>  
</main>

Then we make our text bold.

We can also call JavaScript inside the curly braces.

For instance, we can write:

App.svelte :

<script>  
  let name = "Jane";  
</script><main>  
  <p>Hello {name.toUpperCase()}</p>  
</main>

Then we see Hello JANE displayed on the screen.

Dynamic Attributes

We can add dynamic HTML attribute values to our app.

For instance, we can write the following to add an image with the URL set as a value of a variable:

App.svelte :

<script>  
  let src =  
    "https://images.unsplash.com/reserve/bOvf94dPRxWu0u3QsPjF\_tree.jpg?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=755&q=80";  
</script><main>  
  <img src={src} alt='' >  
</main>

In the code above, we set our image’s URL as the value of variable src .

Then we pass src as the value of src .

Shorthand

If we have something like src={src} , we can shrink it down to {src} .

We can rewrite the example above as follows:

<script>  
  let src =  
    "https://images.unsplash.com/reserve/bOvf94dPRxWu0u3QsPjF\_tree.jpg?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=755&q=80";  
</script><main>  
  <img {src} alt='' >  
</main>

Adding Components

We can add components to our app to divide our app’s code into smaller pieces.

To do that, we import the component and then referencing it in the markup as follows:

Button.svelte :

<script>  
</script><button>  
  Button  
</button>

App.svelte ;

<script>  
  import Button from "./Button.svelte";  
</script><main>  
  <Button />  
</main>

Then we get a button on the screen via the Button.svelte component.

Displaying Raw HTML

We can display Raw HTML in a component by writing the following code:

App.svelte :

<script>  
  let string = "<b>hello</b>";  
</script>

<main>  
  <p>{@html string}</p>  
</main>

The @html tag indicates that we want to display the content as raw HTML. Therefore, we’ll see a bold hello on the screen.

Handling Events

To make our app useful, it has to be able to handle user events.

For instance, we can use the on:click attribute to handle click events of a button as follows:

App.svelte :

<script>  
  let count = 0;  
  const handleClick = () => {  
    count += 1;  
  };  
</script>

<main>  
  <button on:click={handleClick}>  
    Increment  
  </button>  
  <p>{count}</p>  
</main>

In the code above, we have the on:click attribute set to the handleClick function we have in the script tag.

Then when we click the button, it’ll be called, count will be incremented. Then the latest value of count is displayed.

The DOM is automatically updated with the values in script are updated so we don’t have to worry about that.

We can also add variables that are derived from other ones in our code.

For instance, we can add a new variable that has the value which is double the count as follows:

<script>  
  let count = 0;  
  $: doubleCount = count * 2; 
  const handleClick = () => {  
    count += 1;  
  };  
</script>

<main>  
  <button on:click={handleClick}>  
    Increment  
  </button>  
  <p>{count} {doubleCount}</p>  
</main>

The code above has:

$: doubleCount = count * 2;

which is a variable computed from count . It tells Svelte to return the code whenever the referenced value change.

Conclusion

Getting started with Svelte is simple. It uses the same component-based architecture as other major frameworks like React, Angular, and Vue.

Each component has a logic part and a markup part. Events can be handled by setting event handlers on elements.

We can have variables that are derived from others by adding labels to them with the $ .

Categories
JavaScript Vue

Create a Class Vue Compnent with vue-class-component

We can create a Vue component in a class-style component with the vue-class-component package.

To get started, we can use the Vue CLI to create a project with the ‘Manually select features’ option.

Then we select ‘TypeScript’.

Then we press ‘y’ to the question ‘Use class-style component syntax’.

If we want to be able to create class-style Vue.js components in an existing project, we can install the vue-class-component package by running:

npm install --save vue vue-class-component

Then we can create a class-style component by writing:

<template>
  <div>
    <button @click="decrement">-</button>
    {{ count }}
    <button @click="increment">+</button>
  </div>
</template>

<script>
import Vue from 'vue'
import Component from 'vue-class-component'

@Component
export default class Counter extends Vue {
  count = 0

  increment() {
    this.count++
  }

  decrement() {
    this.count--
  }
}
</script>

We imported the Component decorator from vue-class-component package and used it to modified our class to turn it into a component.

Also, we created the Counter class that extends the Vue class.

Like with regular single-file components, we have to export the component code. In this case, we export a class instead of an object with the export keyword.

Then we can have members inside it, including the count state and the increment and decrement methods.

The template section is the same as regular single-file components.

We have the @click directive that calls methods, except the methods are in a class rather than an object.

The count is displayed in a template.

Class-style components is an alternative syntax for creating single-file components.

We can use the vue-class-component package to create class-style components.

The Component decorator and the Vue class lets us create the component class.

The members are accessible in templates as with regular single-file components.