Tips and tricks

How to avoid conflicting mouse events in the editor

When your custom component captures mouse events, this may cause problems in the editor, when users try to drag the component to a position on the grid.

The ComponentContext.mode property will indicate whether the component is currently in view or edit mode. This allows for applying custom behavior to each mode.

You can for example decide to add a CSS class that blocks all pointer events, when the component is in edit mode.

<template>
  <main :class="{ 'edit-mode': editMode }"> 
    <h1>Hello, World!</h1>
  </main>
</template>

<script>
export default {
  name: 'hello-world',
  props: ['context'],
  data() {
    return { editMode: null };
  },
  created() {
    this.editMode = this.context.mode === 'edit';
  }
};
</script>

<style scoped>
  .edit-mode {
    pointer-events: none;
  }
</style>
<script>
  import { onMount } from 'svelte';
  
  export let context;
  let editMode;
  
  onMount(() => {
    editMode = context.mode === 'edit';
  });
</script>

<main class:edit-mode={editMode}>
  <h1>Hello, World!</h1>
</main>

<style>
  .edit-mode {
    pointer-events: none;
  }
</style>

How to prevent click events from opening the detail page in card components

You may encounter a situation where you want to listen for a click event in a card component – for example a button click – but you don't want that event to bubble up causing it to open the device detail page.

This can be achieved by calling the stopPropagation() method on the click event object, or (when you're using a framework that supports this) by using an event modifier that'll call it for you.

<template>
  <!-- prevents click event from bubbling up, causing the device detail page to open. -->
  <button @click.stop="greet">Greet</button>
</template>

<script>
export default {
  name: 'greet-button',
  props: ['context'],
  methods: {
    greet() {
      alert('Hello, ' + this.context.inputs.name + '!');
    }
  }
};
</script>

<style scoped></style>
<script>
  export let context;
  
  function greet() {
    alert('Hello, ' + context.inputs.name + '!');
  }
</script>

<!-- prevents click event from bubbling up, causing the device detail page to open. -->
<button on:click|stopPropagation={greet}>Greet</button>

<style></style>
const template = document.createElement('template');
template.innerHTML = `<button id="button">Greet</button>`;

class GreetButton extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.greet = this.greet.bind(this);
  }

  connectedCallback() {
    this.shadowRoot.appendChild(template.content.cloneNode(true));
    this.shadowRoot.getElementById('button').addEventListener('click', this.greet);
  }
  
  disconnectedCallback() {
    this.shadowRoot.getElementById('button').removeEventListener('click', this.greet);
  }
  
  greet(event) {
    // prevents click event from bubbling up, causing the device detail page to open.
    event.stopPropagation();
      
    alert('Hello, ' + this.context.inputs.name + '!');
  }
}

customElements.define('greet-button', GreetButton);

Did this page help you?