如何在 DOM 中不存在的元素中使用 Rx.Observable.fromEvent?

How to use Rx.Observable.fromEvent in an element that does not exist in the DOM yet?

使用常规 JS 和 Jquery 你可以做类似 $(document).on('click', '#id', function () { // whatever }) 的事情。这允许我们在 DOM 中可能不存在的元素中添加事件。我想使用 Rx.Observable.fromEvent(ele, 'click') 来做同样的事情——我需要这样做,因为元素是在另一个流中创建的。这可能吗?


上下文

我正在努力实现的一些背景。我正在关注 The introduction to Reactive Programming you've been missing。建议的练习是:

  1. 从 GitHub API
  2. 获取用户
  3. 显示三个用户作为要关注的建议;
  4. 每个用户应该有一个 "remove" 按钮;
  5. 每当单击删除按钮时,删除该建议并从缓冲区加载另一个;

直到加载三个建议的部分都非常顺利。例如:

Rx.Observable
    .fromEvent($('#refresh'), 'click')
    .startWith('start up click')
    .map(() => Math.floor(Math.random() * 500))
    .map(offset => `${GITHUB_API}?since=${offset}`)
    .map(url => jQuery.getJSON(url))
    .flatMap(promisse => Rx.Observable.from(promisse))
    .map(users => users.slice(0, 3))
    .do(_ => $('#users').empty())
    .flatMap(users => users)
    .map(user => createItem(user))
    .subscribe(user => $('#users').append(user));

// Just an example for creating the elements
function createItem(user, idx) {
  return $(`
    <li class="item-wrapper horizontal" >
      <img src="${user.avatar_url}" class="rounded-circle" width="50" height="50">

      <div class="item-infos-wrapper vertical">
        <span class="font-weight-bold">${user.login}</span>
        <span class="font-weight-normal">What can we put in here?</span>
      </div>

      <button id="close${idx}" type="button" class="btn btn-outline-danger btn-sm item-action">remove</button>
    </li>
  `);
}

根据我对上述文章的理解,处理项目删除的想法是将 combineLatest 与 "remove button clicked" 和 "requestStream" 流(包含API), 在创建元素的管道中提供组合数据。我目前的问题是从删除按钮点击流和请求流构建这个复古馈送到创建元素的消费者。

您可以这样做,但我不清楚 idx 的来源。是用户的属性吗?

Rx.Observable
    .fromEvent($('#refresh'), 'click')
    .startWith('start up click')
    .map(() => Math.floor(Math.random() * 500))
    .map(offset => `${GITHUB_API}?since=${offset}`)
    .map(url => jQuery.getJSON(url))
    .flatMap(promisse => Rx.Observable.from(promisse))
    .map(users => users.slice(0, 3))
    .do(_ => $('#users').empty())
    .flatMap(users => users)
    .map(user => createItem(user)) //at this point we have a listItem in the stream

    // from this point it's changed

    .tap(listItem => $('#users').append(listItem)) //append to users, but keep the listItem in the stream
    .map(listItem => $(listItem).find('button')[0]) //get the button element
    .mergemMap(closeButton => fromEvent(closeButton, 'click')) //subscribe to click on the button and merge all the clicks into one stream
    .subscribe((event: MouseEvent) => {
        console.log('clicked', event); //a close button was clicked...
    });

这是一种在单击按钮时删除 li 的方法:

Rx.Observable
    .fromEvent($('#refresh'), 'click')
    .startWith('start up click')
    .map(() => Math.floor(Math.random() * 500))
    .map(offset => `${GITHUB_API}?since=${offset}`)
    .map(url => jQuery.getJSON(url))
    .flatMap(promisse => Rx.Observable.from(promisse))
    .map(users => users.slice(0, 3))
    .do(_ => $('#users').empty())
    .flatMap(users => users)
    .mergeMap(user => {
        const listItem = createItem(user);
        $('#users').append(listItem);

        const closeButton = $(listItem).find('button')[0];
        return Rx.Observable.fromEvent(closeButton, 'click').first().tap(_ => listItem.remove());
    })
    .subscribe();