我在理解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>
答案 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的异步领域,它就会停留在那里。
不幸的是,fileArray
(scan
的两个可观察变体)当前不在库中,但是您可以将其编写为
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();
}
}