Массив поля угловой составляющей не заполнен Observable - PullRequest
0 голосов
/ 07 мая 2019

У меня проблема с пониманием rxjs Наблюдаемое сотрудничество с угловыми компонентами и их жизненными циклами (?).Теперь я опишу код, вставленный ниже.

Я получил CartComponent, который содержит массив файлов, которые были добавлены в корзину.Существует сервис, который предоставляет наблюдаемые, которые добавляют или удаляют файлы из filesArray (я использую флажок для добавления / удаления).После добавления пары файлов в корзину я ожидал, что смогу использовать filesArray в SearchComponent (я использовал 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 ]

1 голос
/ 07 мая 2019

Делайте не используйте Observables таким образом в CartComponent.Вместо этого напишите:

@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 никогда не вызывается - если вы пишете вызывающий код, этот код никогда не узнает, когда fileArray изменилось.

Интуитивно, вы пытаетесь «сбежать» из Observable, чтобы вернуть свои изменения в статический мир компонента.Это просто невозможно.Как только вычисление происходит в асинхронной стране Обсерваторий, оно остается там.


К сожалению biscan() (изменение с двумя наблюдениями scan) в настоящее время не находится вбиблиотека, но вы можете написать это как

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();
     };
   });

Редактировать: исправлены опечатки в biscan()

0 голосов
/ 07 мая 2019

Я решил эту проблему с помощью 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();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...