角组件字段数组未由Observable填充

时间:2019-05-07 12:49:27

标签: arrays angular rxjs observable

我在理解rxjs与Angular组件及其生命周期(?)的可观察合作方面遇到问题。我现在将在下面描述粘贴的代码。

我得到了CartComponent,它保存已添加到购物车中的文件数组。 有一项服务提供了可观察的东西,可以在filesArray中添加或删除文件(我使用复选框来添加/删除)。在将几个文件添加到购物车后,我希望能够在SearchComponent中使用filesArray(我使用DI)。不幸的是,尽管filesArray的内容正确显示在购物车视图中,但在该范围内为空。我不明白这种行为。

为什么数组为空,如何解决该问题?请帮忙。

CartComponent:

@Component({
  selector: 'app-cart',
  templateUrl: './cart.component.html',
  styleUrls: ['./cart.component.css']
})
export class CartComponent implements OnInit, OnDestroy {
  filesArray: file[] = [];

  constructor(private modalService: NgbModal, private cartService: CartService) {
  }

  open(content) {
    this.modalService.open(content);
  }

  ngOnInit(): void {
    this.cartService.addFileToCart$.pipe(
      takeUntil(this.componentDestroyed)
    ).subscribe(file => {
      this.filesArray = [...this.filesArray, file];
    });

    this.cartService.removeFileFromCart$.pipe(
      takeUntil(this.componentDestroyed)
    ).subscribe(file => {
      const fileIndex = this.filesArray.indexOf(file);
      this.filesArray.splice(fileIndex,1);
    });
  }

  private componentDestroyed: Subject<void> = new Subject();

  ngOnDestroy(): void {
    this.componentDestroyed.next();
    this.componentDestroyed.unsubscribe();
  }

}

SearchComponent:

@Component({
  selector: 'app-search',
  templateUrl: './search.component.html',
  styleUrls: ['./search.component.css']
})
export class SearchComponent implements OnInit {

  constructor(private cartComponent: CartComponent) {
  }

  private checkOrderedFiles() {
    console.log(this.cartComponent.pcFilesArray); //empty
  }

CartService:

@Injectable({
  providedIn: 'root'
})
export class CartService {

  addFileToCart$: Subject<PCFile> = new Subject();
  removeFileFromCart$: Subject<PCFile> = new Subject();

  constructor() { }
}

复选框更改事件处理程序-我在此处向主题发出值:

addOrRemoveFileFromCart(checkbox, item) {
  if(checkbox.checked) {
    this.cartService.addFileToCart$.next(item);
  } else {
    this.cartService.removeFileFromCart$.next(item);
  }
}

编辑:

public readonly files = this.cartService.addFileToCart$.pipe(
    scan((filesArray: any, file) => [...filesArray, file], []),
    share()
);

模板

<div *ngFor="let file of files | async">
  {{file.id}}
</div>

2 个答案:

答案 0 :(得分:1)

不要在CartComponent中使用Observables that way。而是写:

javax-servlet-api:4.0.1

在模板中,无论您当前使用的是@Component({ selector: 'app-cart', templateUrl: './cart.component.html', styleUrls: ['./cart.component.css'] }) export class CartComponent { public readonly files = biscan( this.cartService.addFileToCart$, this.cartService.removeFileFromCart$, (filesArray, file) => [filesArray, file], (filesArray, file) => filesArray.filter(f => f !== file), [] ), startWith([]), ); constructor(private modalService: NgbModal, private cartService: CartService) { } open(content) { this.modalService.open(content); } } ,还是使用files | async

在其他组件中,无论您当前使用的是fileArray还是files,在任何地方都使用fileArray 作为可观察对象

潜在的问题是,pcFileArray从未被调用-如果您编写调用它的代码,则该代码将永远不知道checkOrderedFiles何时更改。

直觉上,您正在尝试从Observable中“退出”,以使更改返回到组件的静态世界。那是不可能的。一旦计算进入Observables的异步领域,它就会停留在那里。


不幸的是,fileArrayscan的两个可观察变体)当前不在库中,但是您可以将其编写为

biscan()

编辑:修复了const biscan = (leftObs, rightObs, leftFcn, rightFcn, initialValue) => new Observable(observer => { let acc = initialValue; // this function must be called *twice* (once for left, // once for right) before the observer is completed. let complete = () => { complete = () => observer.complete(); }; const makeSub = (obs, f) => obs.subscribe(v => { acc = f(acc, v); observer.next(acc); }, e => observer.error(e), () => complete() ); const leftSub = makeSub(leftObs, leftFcn); const rightSub = makeSub(rightObs, rightFcn); return () => { leftSub.unsubscribe(); rightSub.unsubscribe(); }; });

中的错别字

答案 1 :(得分:0)

我在马尔沃里奥(Malvolio)的帮助下解决了这个问题(我自己无法确定)。我在下面发布工作代码,因为我想发布的那篇文章有一些语法错误。我在异步管道方面遇到问题,我相信这是因为CartComponent模板的内容位于模式内部。我是通过手动订阅解决的。

export class CartComponent implements OnInit, OnDestroy {
    filesArray;
    private componentDestroyed: Subject<void> = new Subject();

    biscan = (leftObs, rightObs, leftFcn, rightFcn, initialValue) =>
      new Observable(observer => {
        let acc = initialValue;
        let complete = () => observer.complete();
        const makeSub = (obs, f) => obs.subscribe(v => {
            acc = f(acc, v);
            observer.next(acc);
          },
          e => observer.error(e),
          () => complete()
        );
        const leftSub = makeSub(leftObs, leftFcn);
        const rightSub = makeSub(rightObs, rightFcn);
        return () => {
          leftSub.unsubscribe();
          rightSub.unsubscribe();
        };
      });

    public readonly files = this.biscan(
      this.cartService.addFileToCart$,
      this.cartService.removeFileFromCart$,
      (filesArray, file) => {
        filesArray.push(file);
        return filesArray;
      },
      (filesArray, file) => {
        filesArray.splice(filesArray.indexOf(file), 1);
        return filesArray;
      },
      []
    ).pipe(takeUntil(this.componentDestroyed));

    constructor(private cartService: CartService) {}

    ngOnInit(): void {
        this.files.subscribe(files => this.filesArray = files);  
    }

    ngOnDestroy(): void {
        this.componentDestroyed.next();
        this.componentDestroyed.unsubscribe();
    }
}