How to write Xamarin.Forms events in TypeScript?
Tags: xamarin, xamarinforms, typescript, showdev
Published: 2020-03-03 04:49:50

# Events and Commands

Both events and commands can be written in one single pattern.

```typescript

<XF.Button
    command={(e) => this.viewModel.save()}
    />

// OR

<XF.Button
    command={Bind.event((s, e) => this.viewModel.save())}
    />

```

There are two ways you can create event handler, one is simply a lambda function that can accept single parameter. In this expression, you cannot access current control, which may be useful when you are inside a multiple items container such as `ListView` or `CollectionView` or even `BindableLayout`.

You could simply write a function, but sometimes you may need to access enclosing AtomControl and its data or viewModel property.

# Multiple Items Control

```typescript
<XF.CollectionView>
   <XF.CollectionView.itemTemplate>
      <XF.DataTemplate>
          <XF.Label>
             <XF.Label.gestureRecognizers>
                 <XF.TapGestureRecognizer
                      command={Bind.event((s, e) =>
                         this.viewModel.select(s.data) }
                      />
             </XF.Label.gestureRecognizers>
          </XF.Label>
      </XF.DataTemplate>
   </XF.CollectionView.itemTemplate>
</XF.CollectionView>
```

Every item inside items container has an atom control associated with it, to access the data (BindingContext) associated with the control, we need to wrap lambda in `Bind.event` which gives us `data` property.

The syntax is similar to event handler syntax of Xamarin.Forms, with only difference being, `sender` is the AtomControl.

# Data vs BindingContext

In order to improve speed and to keep JavaScript code isolated and consistent throughout different frameworks, we use `data` property instead of `BindingContext` as sometimes you may need to access more JavaScript properties such as `viewModel`/`localViewModel` etc.

Keeping bindings free from underlying platform also reduces amount of possible data transfer between both platforms and reduces possibility of memory leaks.

When you move your code to `Web` or other native platforms, `BindingContext` could be called some different name on different platforms.

# Event Parameter

Event parameter object is serialized in JavaScript using WeakReference, you can call method and get/set property on it. Since it is weak reference, you cannot store it in JavaScript. You can only extract some information and you can store that information with you.

# Dispatch Event

In order to keep event dispatch exactly same as in Html, we have added `CustomEvent` and `dispatchEvent` support for native elements of Xamarin.Forms.

```typescript

export default class MyCustomControl extends AtomXFContentView { 

   ...

   // dispatch..
   this.element.dispatchEvent(new CustomEvent("customEvent", { detail: param }));

   ...
```

Listen for event..

```typescript

   <MyCustomControl
       eventCustomEvent={Bind.event((s, e) => this.viewModel.onEvent(e.detail))}
       />

```

Even though such event does not exist in Xamarin.Forms element, you can still subscribe to it and listen for it, it works exactly similar to HTML events.

# Event Execution

All events are fired under main UI thread, so it is recommended that do not do any long processing in event handler.

# Async Event Handler

All event handlers are assumed to be async by default, so if you return a promise in your event handler, error will be caught and it will be displayed in console.

# `@Action()` decorator

In order to display an alert for any exception, you can decorate your event handler with `@Action()` decorator.

```typescript
   @Action({ validate: true })
   public async save() {
      ....
   }
```

## Validate
Setting validate true, will fire up all validations and action will be executed if only all validations pass through.

## Success
If set to true, or a non empty string, an alert message box will be displayed after successful execution.

# Memory Leaks

Since dealing with multiple runtimes can quickly introduce memory leaks, Web Atoms systematically disposes every event registered via TSX code. It is better if you register events only through TSX.

Otherwise, every event registration done in JavaScript returns a disposable, which you can add to your viewModel. View model has collection of disposables and it disposes every registered disposable when view model is disposed.