WICG / observable

Observable API proposal
https://wicg.github.io/observable/
Other
543 stars 12 forks source link

Data Sinks support #119

Open dariomannu opened 4 months ago

dariomannu commented 4 months ago

I've seen Observables only proposed as event sources, but why not support them as data sinks, as well?

element
  .observe('keypress')
  .map(e => e.keyCode)
  .sink(otherElement.innerHTML)
  .sink(yetAnotherElement.appendChild)

Using a hypothetical .sink() here as it sounds more digestible for the sake of presentation, but it'd be just an optional alias for .subscribe(), which would work just as well, I guess.

also:

.sink(otherElement.innerText)
.sink(otherElement.textContent)
.sink(otherElement.innerHTML)
.sink(otherElement.class)
.sink(otherElement.classList)
.sink(otherElement.class.someClassNameToToggle)
.sink(otherElement.prependChild)
.sink(otherElement.appendChild)
.sink(otherElement.insertAt(pos))
.sink(otherElement.insertBefore(pos))
.sink(otherElement.insertAfter(pos))
.sink(otherElement.dataset)
.sink(otherElement.dataset.someValue)
.sink(otherElement.style)
.sink(otherElement.style.backgroundColor)
.sink(document.title)

Essentially, any value in the DOM that can be set imperatively, could become an observer.

Even entire elements could become observers, by sinking an Object or a Map into them, so that onclick, onmouseover and style can be set in one go:

element
  .observe(someEvent)
  .map(e => ({
    onclick: () => doSomething,
    onmouseover: () => doSomething,
    style: {
       color: 'red'
   }),
  .sink(otherElement)

Similarly, for complex attributes such as style or dataset:

element
  .observe(someEvent)
  .map(e => ({
       color: 'red',
       backgroundColor: 'blue'
   }),
  .sink(otherElement.style)

Using higher-order observables each attribute would be set individually when the various inner observables emit:

element
  .observe(someEvent)
  .map(e => ({
    onclick: Observable1(),
    onmouseover: Observable2(),
    style: Observable3(),
    innerHTML: Observable4(),
  .sink(otherElement)

Finally, if the above doesn't taste FRP enough, you might want to consider setting up the whole pipeline starting from the target, backwards, as in a pull model, as follows:

targetElement.innerHTML =
  sourceElement
    .subscribe('click')
    .scan(x=>x+1,0)
    .map(n => `you clicked ${n} times`)

Could something like this fit into this spec?