How to write Xamarin.Forms events in TypeScript?
Akash Kava
Posted on March 3, 2020
Events and Commands
Both events and commands can be written in one single pattern.
<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
<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.
export default class MyCustomControl extends AtomXFContentView {
...
// dispatch..
this.element.dispatchEvent(new CustomEvent("customEvent", { detail: param }));
...
Listen for event..
<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.
@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.
Posted on March 3, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.