Components and events
Your own elements
Section titled “Your own elements”Very quickly you will want to create your own elements: specific pages, controls…
Let us take the simplest example and flesh it out.
// import the required elementsimport { Application, Button, VBox } from 'x4js';
// create the applicationconst app = new Application( );
// create the main viewconst frame = new VBox( { cls: "fit", // the fit class fills the parent container content: [ new Button( { label: "Hello world" } ), ]});
// declare it as the main view of the applicationapp.setMainView( frame );Here the main view is a VBox object: children are placed one under the other. In most cases this kind of construction is not enough: you need to respond to events, and the content itself is better carried by the object. Here is how:
import { Application, BoxProps, Button, VBox } from 'x4js';
// this time we declare a class that extends VBoxclass MainView extends VBox { constructor( props: BoxProps ) { super( props );
this.addClass( "fit" );
this.setContent( [ new Button( { label: "Hello, I'm a custom class" } ), ]); }}
const app = new Application( );app.setMainView( new MainView( { } ) );We created a MainView class that derives from VBox and implements its own constructor.
Handling events
Section titled “Handling events”We are now going to catch the click on the button. To do so, we tell the button whom to call:
class MainView extends VBox { constructor( props: BoxProps ) { super( props );
this.addClass( "fit" );
this.setContent( [ new Button( { label: "Hello, I'm a custom class", click: ( ) => this.onClick( ), // call my onClick method }), ]); }
// called by the button private onClick( ) { alert( "I have been clicked" ); }}Following this principle, you create software “bricks”: login, user form, lists, dialogs…
Subscribing later
Section titled “Subscribing later”Passing the handler in the properties is the short form. You can also subscribe later, with on:
const save = new Button( { label: "Save" } );
const sub = save.on( "click", ( ) => console.log( "saved" ) );
// to unsubscribesub.off( );Firing your own events
Section titled “Firing your own events”An application component declares three things: its properties, its events, and the shape of each event.
import { Button, ComponentEvent, ComponentEvents, ComponentProps, EventCallback, HBox, Label } from 'x4js';
// what the event carriesinterface EvRename extends ComponentEvent { name: string;}
// the events of the componentinterface TitleBarEvents extends ComponentEvents { rename: EvRename;}
// its properties, including the handler in short forminterface TitleBarProps extends ComponentProps { title: string; rename?: EventCallback<EvRename>;}
class TitleBar extends HBox<TitleBarProps,TitleBarEvents> { declare protected refs: { title: Label };
constructor( props: TitleBarProps ) { super( props );
// connect the handlers received in the properties this.mapPropEvents( props, "rename" );
this.setContent( [ this.refs.title = new Label( { flex: 1, text: props.title } ), new Button( { label: "Rename", click: ( ) => this.rename( "New title" ) } ), ]); }
private rename( name: string ) { this.refs.title.setText( name ); this.fire( "rename", { name } ); }}It is then used like the components provided, and the editor knows its properties and its events:
const bar = new TitleBar( { title: "Untitled", rename: ( ev ) => console.log( ev.name ),});Reaching your children: refs
Section titled “Reaching your children: refs”In the example, the label is stored in this.refs.title while the content is being built. refs is a typed directory of the children you need to reach again later. Declare its shape in the class, and write the assignment directly in the content array.
A child you never need to come back to does not have to be in it.
- State and messages: share a state and broadcast messages across the application.
- Standard controls: what x4js already provides.