path-listener
path-listener implements the tosijs observer model. Although these events
are exported from tosijs they shouldn't need to be used very often. Mostly
they're used to manage state.
touch(path: string) and .touch()
This is used to inform xin that a value at a path has changed. Remember that
xin simply wraps an object, and if you change the object directly, xin won't
necessarily know about it.
The two most common uses for touch() are:
- You want to make lots of changes to a large data structure, possibly over a period of time (e.g. update hundreds of thousands of values in a table that involve service calls or heavy computation) and don't want to thrash the UI so you just change the object directly.
- You want to change the content of an object but need a something that is bound to the "outer" object to be refreshed.
Every BoxedProxy also has a .touch() method, so you can call it directly
on any proxied value:
app.user.name.touch() // force update for this scalar
app.user.touch() // force update for the whole object
app.items[2].touch() // force update for a list item
Id-path synthesis
When you touch a path that contains an array index (e.g. items[2] or
items[2].name), touch() automatically synthesizes the equivalent id-path
touches (e.g. items[id=abc] or items[id=abc].name). This means that
.touch() on list items correctly updates DOM elements bound via idPath,
even when you've mutated the underlying data behind the proxy's back.
observe() and unobserve()
const listener = observe(
path: string | RegExp | (path: string) => boolean,
(changedPath: string) => {
...
}
)
// and later, when you're done
unobserve(listener);
observe(…) lets you call a function whenever a specified path changes. You'll
be passed the path that changed and you can do whatever you like. It returns
a reference to the listener to allow you to dispose of it later.
unobserve(listener) removes the listener.
This is how binding works. When you bind a path to an interface element, an observer is created that knows when to update the interface element. (If the binding is "two-way" (i.e. provides a
fromDOMcallback) then aninputorchangeevent that hits that element will update the value at the bound path.
async updates()
You can await updates() or use updates().then(…) to execute code
after any changes have been rendered to the DOM. Typically, you shouldn't
have to mess with this, but sometimes—for example—you might need to know
how large a rendered UI element is to adjust something else.
It's also used a lot in unit tests. After you perform some logic, does it appear correctly in the UI?