从角度为6的更改项的列表组件中获取selectItems的反应方式

时间:2018-10-09 19:36:30

标签: angular rxjs

我正在寻找实现这一目标的方法:

我有一个列表视图组件,其中有一个子列表。 子级列表可能会随着时间而变化(例如由于过滤器) 列表视图组件具有可观察到的渲染项。

孩子有一个附加的list-item指令, 这样,可以通过该指令从父组件中查询它们(因此,在列表中呈现哪种类型的组件都没有关系,它们只需要应用该指令即可)

该指令已选择“可观察的” $

现在如何在包含当前选定项目的列表组件内部获得一个可观察对象?

我在stackblitz上做了一个例子,为简便起见,我的应用程序组件是此处的listview组件:

https://stackblitz.com/edit/angular-rktm99

更新 我正在寻找一种方法来组合流以使用选定的ListViewItemDirectives到达流。其他事情起作用,我被这个特殊的事情所困扰: 我有一个可观察的contentChildren流,每个孩子都有一个可观察的属性selected $。我正在研究如何将它们组合在一起(我想我需要像mergeMap或switchMap这样的运算符?)

2 个答案:

答案 0 :(得分:0)

我猜想指令选择器出了点问题,因为 length 即将 0 this.items

  @ViewChildren(ListViewItemDirective)
  items: QueryList<ListViewItemDirective>;

  constructor() {
    setInterval(() => {
      console.log('aaaaavvvv');
      console.log(this.items);
      }, 1000);
  }

现在将选择器更改为

@Directive({
  selector: 'li'
})

长度正在增加

QueryList {dirty: false, _results: Array[138], changes: {…}, length: 138…}
changes: EventEmitter
dirty: false
first: ListViewItemDirective
last: ListViewItemDirective
length: 138
_results: Array[138]

答案 1 :(得分:0)

首先,我认为我们可能有一个更好的解决方案,因为当前的情况看起来像是黑客。

删除ListViewItemDirective中的重复项。

@Directive({
  selector: '[list-view-item]'
})
export class ListViewItemDirective {
  selected$: Subject<boolean> = new BehaviorSubject(false);

  @Input('list-view-item') listViewItem;

  @HostBinding('class.selected')
  get isSelectedClass() {
    return this.selected$.getValue();
  }

  @HostListener('click')
  clickEvent() {
    this.selected$.next(!this.selected$.getValue());
  }
}

ContentChildren更改为ViewChildren,并将其“转换”为Observable。 当ViewChildren发出时,我们将得到Observable<directive[]>,请使用directiveToObservable得到Observable<Observable<listViewItem>[]>combineLatest会将其解包到Observable<listViewItem[]>

function directiveToObservable(directive) {
  return directive
    .selected$
    .pipe(map(selected => selected ? directive.listViewItem : null))
}

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterContentInit {
  name = 'Angular';
  options = [];
  listItems = new BehaviorSubject([]);

  selectedItems$ = this.listItems.pipe(
    // hack ExpressionChangedAfterHasBeenChacked, as a changes in child will change parent
    delay(0),
    switchMap(
      directives => combineLatest(
        directives.map(directiveToObservable),
      ),
    ),
    map(list => list.filter(el => !!el)),
  );

  data$ = timer(0, 2000).pipe(
    tap((i) => this.options.push('option ' + i)),
    map(i => this.options)
  );


  @ViewChildren(ListViewItemDirective)
  set items(items: QueryList<ListViewItemDirective>) {
    this.listItems.next(items.toArray())
  }

}

Example