# Binding

Apart from JSX properties, you can use following ways to bind properties and bind events.
1. One Way Binding by using `Bind.oneWay`.
2. One Way Async Binding by using `Bind.oneWayAsync`, which offers cancellation token.
3. Two Way Binding by using `Bind.twoWaysImmediate`.
4. Event binding by using `event-*` prefix.
5. Style binding by using `style-*` prefix.

## One Way Binding

Building data aware application requires updating UI automatically when data changes. One way binding refreshes element automatically when data is modified by any one. To make it simpler, you have to write your binding expressions in square brackets []

```tsx
    export default class TimerPage extends ContentPage {

        public time: Date;

        public async init() {
            const timer = setInterval(
                (x) => x.time = new Date(),
                1000,
                this);
            
            // this will dispose the
            // timer when the page is
            // destroyed
            this.registerDisposable({
                dispose: () => {
                    clearInterval(timer);
                }
            });

            this.render(<div>
                <div text={Bind.oneWay(() =>
                    `Current time is ${this.time}`)}/>
            </div>);
        }

    }
```

> Internally, whenever any thing that is inside property path gets updated, expression is evaluated and property is set. If anything is evaluated as `undefined`, update is skipped. If anything is `null`, entire expression is evaluated as `null` and no error is reported.

### Sample
For more, please visit,
https://stackblitz.com/~/github.com/web-atoms-samples/binding

## Expression

One way binding can be any valid TypeScript expression. You can call any method. Make sure you import corresponding module in start of the file.

```tsx
    <span
        text={Bind.oneWay(() =>
            `${this.firstName} ${this.lastName}`)}></span>
```

You must bind UI to `fullName`, instead of writing custom expressions. Benefit is, you can unit test it, you do not have to repeat expressions for different platform and you can perform formatting inside view model that is consistent for different platforms.

### Sample
For more, please visit,
https://stackblitz.com/~/github.com/web-atoms-samples/binding
## Two Way Binding

```tsx
export default class TwoWayBindingPage extends ContentPage {

    public model = {
        username: "",
        password: "",
        passwordAgain: ""
    }

    public async init() {

        this.render(<div>
            <Form2>
                <FormField
                    label="Username"
                    required={true}
                    error={BindError({ value: () => this.model.username})} >
                    <input
                        value={Bind.twoWaysImmediate(() => this.model.username)}/>
                </FormField>
                <FormField
                    label="Password"
                    required={true}
                    error={BindError({ value: () => this.model.password})}>
                    <input
                        type="password"
                        value={Bind.twoWaysImmediate(() => this.model.password)}/>
                </FormField>
                <FormField
                    label="Password Again"
                    error={BindError({ value: () => this.model.password === this.model.passwordAgain, isValid: (v) => !v || v === "true"})}>
                    <PasswordBox
                        value={Bind.twoWaysImmediate(() => this.model.passwordAgain)}/>
                </FormField>
                <FormField label="">
                    <button
                        type="submit" 
                        text="Signup"/>
                </FormField>
            </Form2>
        </div>);
    }
}
```

This will update username inside model whenever user modifies text inside edit. You can also bind `checked` property of checkbox. 

For input element in HTML, binding is only updated on `change` event. If you want to update binding every time a key is pressed. You can use specify name of events to update bindings on as shown below.

```tsx
    <input 
        type="search"
        value={Bind.twoWaysImmediate(() => this.search))}/>
```

In above example, search property in `control` is set every time a key is pressed.

You can bind properties of AtomControl derived control.
```tsx
    <ComboBox
        selectedItem={Bind.twoWays(() => this.selectedItem)}
        />
```
### Sample
For more, please visit,
https://stackblitz.com/~/github.com/web-atoms-samples/binding
## Style

Style extension can be used in one time/one way binding. It cannot be used for two way binding.

```jsx
export default class StylePage extends ContentPage {

    private color: string = "blue";

    private bgColor: string = "lightgreen";

    public async init() {

        this.headerRenderer = () => <div data-layout="row">
            Color: 
            <ComboBox
                items={colors()}
                selectedItem={Bind.twoWaysImmediate(() => this.color)}
                />
            Background: 
            <ComboBox
                items={bgColors()}
                selectedItem={Bind.twoWaysImmediate(() => this.bgColor)}
                />
        </div>;

        this.render(<div>
            <p>This is a simple text.</p>
            <p>This is a <span style-color="red">red colored text</span></p>
            <p>This is a text with
                <span
                    style-margin-left="5px"
                    style-margin-right="5px"
                    style-color={Bind.oneWay(() => this.color)}
                    style-background-color={Bind.oneWay(() => this.bgColor)}
                    >chosen color and background color</span>
                from the drop down.</p>
        </div>);
    }

}
```
You can set properties of style with `style-` prefix.
This helps in setting individual styles separately without having to worry about concating and escaping strings correctly.

If only one style property is updated using `Bind.oneWay`, it will not cause entire style attribute to be rewritten, it will only update single property of the style.
### Sample
For more, please visit,
https://stackblitz.com/~/github.com/web-atoms-samples/binding
## Event Binding
Event binding extension allows you to subscribe events. This extension also safely unsubscribes automatically when component is disposed.

```jsx
export default class EventPage extends ContentPage {

    public async init() {
        this.render(<div data-layout="vertical-flex-center-items">
            <button
                event-click={() => PopupService.alert({ message: "Button was clicked"})}
                >Click me</button>
            <ComboBox
                event-input={() => PopupService.alert({ message: "Selection changed... "})}
                items={["One", "Two", "Three"]}
                />

            <a
                href="https://google.com"
                text="https://google.com"/>

            <div>In this example, we will prevent clicking of link by capturing event here.</div>
        </div>);

        const preventLinkClick = async (e: MouseEvent) => {
            let start = e.target as HTMLElement;
            while (start) {
                if (start.tagName === "A") {
                    e.preventDefault();
                    e.stopPropagation();
                    await PopupService.alert({ message: "Clicking outside links not permitted"});
                    return;
                }
                start = start.parentElement;
            }
        };

        // bindEvent will also remove the eventListener when the component will be disposed.
        this.bindEvent(this.element, "click", preventLinkClick, null , { capture: true });
    }

}
```

> Although event binding is simple, we recommend not to use to many
> event binding on one page, instead use event re routing. It will
> reduce memory usage and cpu usage. Creating and attaching event 
> listener takes significant amount of time and memory.

For AtomRepeater in HTML, we recommend using event re routing instead of event binding, as event binding is expensive for more number of items.

```tsx
    <AtomRepeater
        items={Bind.oneWay(() => this.viewModel.items)}
        itemRenderer={(item) => <div>
                <span
                    text={item.label}/>
                <button
                    data-click-event="delete-item"}
                    text="Delete"/>
            </div>
        }/>
```
### Sample
For more, please visit,
https://stackblitz.com/~/github.com/web-atoms-samples/binding

# How Web Atoms manages bindings?

We wanted to make binding extremely easy without having to code too much, so we created a Binder that creates additional fields in an object and manages refresh callbacks. The reason we did not use `Object.watch` is, it does not support refreshing a readonly property. Binder allows refreshing property of any object, so anyone is watching for any change, their callback is invoked by Binding. Binding does not maintain central repository, this makes updates very fast, with little overhead in memory as every refresh handle exists inside the target object, it is also easy to debug and visualize binding.

Also, you do not need to explicitly create getter and setter to support binding, whenever Binder tries to watch an object, if object has getter and setter, it assumes that creator will refresh property. If object is a plain object without any prototype, Binder will convert members to getter/setter and inject code to refresh property inside setter.

This is the reason, you will not see any `watch` being explicitly called to watch an object, in fact, you will never need to worry about how to refresh the UI. If UI has one way binding, it will refresh automatically when it is updated. Attributes `@Watch` and `@Validate` works magically.

You never have to think, what to observe, when to observe and where to observe.