---
title: Respond to Events with SJS
---

## Background information

Frequent user interactions can make a miniapp freeze. For example, A and B are two elements on a page. When the user makes a `touchmove` gesture on A, B is required to move with A. `movable-view` is a typical example. The response process for a `touchmove` event is as follows.

1. A `touchmove` event is transferred from the view layer (`Webview`) to the logic layer (App Service).

2. The `touchmove` event is handled at the logic layer (App Service), and then the position of B is changed through `setData`.

A response to `touchmove` involves two rounds of communication between the logic layer and rendering layer, as well as a rendering. It takes a lot of time. Moreover, `setData` rendering blocks the execution of other scripts, leading to delays in the interactive animations.

## Implementation solution

The basic idea of this solution is to reduce the number of communications and respond to events at the view layer (`Webview`). The framework of a miniapp consists of the view layer (`Webview`) and logic layer (App Service) to achieve an easy control. Previously, the developer's code could only run at the logic layer (App Service). However, this solution requires that the code run at the view layer (`Webview`) instead. The figure below shows the process:

<Image src="/images/framework/sjssolution.en-US.png" />

The SJS function can only be used to respond to the events of built-in components of a miniapp, rather than events of custom components. In addition to purely logic operations, the SJS function can also access and set the `class` and style of a component by using the encapsulated `ComponentDescriptor` instance. Setting `style` and `class` is sufficient for interactive animations. The following code block describes the SJS function:

```js
const sjsFunction = function (event, ownerInstance) {
  const instance = ownerInstance.selectComponent('.classSelector'); // Return the component instance
  instance.setStyle({
    'font-size': '14px',
  });
  instance.getDataset();
  instance.setClass(className);
  // ...
  return false; // The event is not propagated to the parent node, which means both stopPropagation and preventDefault are called.
};
```

For the input parameter `event`, the `event.instance` parameter is added to the event objects of the miniapp and indicates the `ComponentDescriptor` instance of the component that triggers the event. `ownerInstance` represents the `ComponentDescriptor` instance of the component where the component triggering the event is located. If the component triggering the event is located inside the page, `ownerInstance` represents a page instance.

`ComponentDescriptor` is defined as follows:

| Method                        | Parameter                      | Description                                                                                                                                                                       |
| ----------------------------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| selectComponent               | selector object                | Return the `ComponentDescriptor` instance of the component.                                                                                                                       |
| selectAllComponents           | selector object array          | Return the array of `ComponentDescriptor` instances of the component.                                                                                                             |
| setStyle                      | Object/string                  | Set the component style. The style set takes precedence over that defined in the component `tyml`. It does not support setting the style of the topmost page.                     |
| addClass/removeClass/hasClass | string                         | Set the component `class`. The `class` set takes precedence over the `class` defined in the component `tyml`. It does not support setting the `class` of the topmost page.        |
| getDataset                    | None                           | Return the `dataset` object of the current component or page.                                                                                                                     |
| callMethod                    | (funcName:string, args:object) | Call the function defined by the current component or page at the logic layer (App Service). `funcName` indicates the function name and `args` indicates the function parameters. |
| requestAnimationFrame         | Function                       | It is the same as the native `requestAnimationFrame`. Set the animation.                                                                                                          |
| getState                      | None                           | Return an `object`. This method is used when a local variable needs to be stored for future use.                                                                                  |
| triggerEvent                  | (eventName, detail)            | It is the same as the component `triggerEvent`.                                                                                                                                   |
| getComputedStyle              | `Array.<string>`               | This parameter is the same as [SelectorQuery](/en/miniapp/develop/miniapp/api/tyml/NodesRef/NodesRef) `computedStyle`.                                                            |
| setTimeout                    | (Function, Number)             | It is the same as the native `setTimeout`. Create the timer.                                                                                                                      |
| clearTimeout                  | Number                         | It is the same as the native `clearTimeout`. Clear the timer.                                                                                                                     |
| getBoundingClientRect         | None                           | The return value is the same as that of [SelectorQuery](/en/miniapp/develop/miniapp/api/tyml/NodesRef/boundingClientRect) `boundingClientRect`.                                   |
| eventChannel                  | None                           | `EventChannel` object, two `EventChannel` objects can use `emit` and `on` methods to send and listen events to each other                                                         |

**SJS runs at the view layer (`Webview`), where fewer events can be handled. Therefore, a mechanism is required to communicate with your code at the logic layer (App Service). The `callMethod` is a method in SJS that calls your code at the logic layer (App Service). `SjsPropObserver` is the mechanism by which your code at the logic layer (App Service) calls the SJS logic.**

## How it works

### Define events using `tyml`:

```tyml
<sjs module="test" src="./test.sjs"></sjs>

<view change:prop="{{test.propObserver}}" prop="{{propValue}}" bind:touchmove="{{test.touchmove}}" class="movable"></view>
```

The `change:prop` above (a property prefixed by `change:`) triggers the SJS function when the `prop` value is set. Its value must be enclosed with `{{}}`. Similar to the `observer` property in `properties` defined by `Component`, calling `setData({propValue: newValue})` will trigger the SJS function.

**Note**: The SJS function must be enclosed with `{{}}`. The SJS function is triggered when the `prop` value is set, rather than just the value being changed. Therefore, the `SjsPropObserver` function is called when the page is initialized.

The event handler and the functions triggered when properties are changed are defined in and exported from the SJS file `test.sjs`:

```js
// event: the event object.
// ownerInstance: represents the ComponentDescriptor instance of the component where the component triggering the event is located. If the component triggering the event is located inside the page, ownerInstance represents a page instance.
const touchmove = function (event, ownerInstance) {
  console.log('log event', JSON.stringify(event));
};

// newValue: new value.
// oldValue: old value.
// ownerInstance: represents the ComponentDescriptor instance of the component where the component triggering the event is located. If the component triggering the event is located inside the page, ownerInstance represents a page instance.
// instance: represents the ComponentDescriptor instance of the component triggering the event.
const propObserver = function (newValue, oldValue, ownerInstance, instance) {
  console.log('prop observer', newValue, oldValue);
};

export default {
  touchmove: touchmove,
  propObserver: propObserver,
};
```
