ПоведениеТема RxJs angular2

Я не получаю значение ответа в компоненте с BehaviorSubject. Получил и сдал в сервис.

Я запускаю HTTP из службы на защите маршрута.

оказание услуг:

@Injectable()
export class ProjectsService {
projects: Subject<Project[]> = new BehaviorSubject<Project[]>([]);

load(clientId: string, active: boolean): Observable<boolean> {
    return new Observable<boolean>((obs) => {
        this._api.send(active ? 'projects.getActive' : 'projects.getAll',clientId).subscribe(
            res => {
                let temp = [];
                res.forEach(a => temp.push(new Project(a)));

                if (active) this.projects.next(temp);
                else this.externalProjects.next(temp);
                obs.next(true);
                obs.complete();
            },

            err => {
                obs.next(false);
                obs.complete();
            }
        );
    });
}

составная часть:

ngOnInit(): void {
    // todo: check why not to load already added
    this._projectsListener = this._projectsService.projects.subscribe(a => {
        this.showIntro = a.length ? false : true;
        this.projects = a;
    });
 }

HTML:

<div class="project" [hidden]="!showIntro" *ngFor="let project of projects>
  {{project.title}}
</div>

Он просто получает параметр запроса для параметров HTTP... Guard:

@Injectable()
export class ProjectsGuard implements CanActivate {
   constructor(
       private _projectsService: ProjectsService,
       private _router: Router) {}

   canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
       return this._projectsService.load(next.params['id'], true)
   }
}

Я также пробую NgZone, но я не уверен, что это правильный путь:

load(clientId: string, active: boolean): Observable<boolean> {
    return this._api.send(active ? 'projects.getActive' : 'projects.getAll',clientId)
        .map(res => {
            let temp = res.map(a => new Project(a));

            this._ngZone.run(() => {
                console.log('temp: ', temp);
                if (active) this.projects.next(temp);
                else this.externalProjects.next(temp);
            });

            return true;
        })
        .catch(() => Observable.of(false));
}

введите здесь описание изображения


person Matej Maloča    schedule 19.12.2016    source источник
comment
Какая у вас проблема? Вы можете указать, какую ошибку вы получаете.   -  person Avnesh Shakya    schedule 19.12.2016
comment
Где load() называется? Почему вы используете так много вложенных наблюдаемых?   -  person Meir    schedule 19.12.2016
comment
Я не получаю сообщение об ошибке... просто не отображаю никаких данных... не могу получить HTTP-ответ в компоненте. load() правильно вызывается при защите маршрута (canActivate).   -  person Matej Maloča    schedule 19.12.2016


Ответы (1)


Прежде всего: не подписывайтесь на другой наблюдаемый внутри наблюдаемого. Вместо этого напишите это как поток:

@Injectable()
export class ProjectsService {
projects: Subject<Project[]> = new BehaviorSubject<Project[]>([]);

load(clientId: string, active: boolean): Observable<boolean> {
    return this._api.send(active ? 'projects.getActive' : 'projects.getAll',clientId)
        .map(res => {
                let temp = res.map(a => new Project(a));

                if (active) {
                    this.projects.next(temp);
                } else {
                    this.externalProjects.next(temp);
                }
                return true;
            })
       .catch(() => Observable.of(false));
}

И во-вторых: не подписывайтесь вручную на бесконечный поток, чтобы записать результат в член класса, вместо этого используйте async-pipe:

public projects$: Observable<Project[]> = this._projectsService.projects;
public showIntro$: Observable<boolean> = this.projects$
    .map(projects => projects.length > 0);

ngOnInit(): void {
    // ...nothing to do here
}

Шаблон:

<div class="project" [hidden]="!showIntro" *ngFor="let project of (projects$ | async)>
  {{project.title}}
</div>
....somewhere else:
<div *ngIf="showIntro$ | async">INTRO!</div>

Если ваша проблема с загрузкой все еще сохраняется, вы можете поделиться содержимым метода api.send (если только он не вызывается наверняка).

Одной из возможностей может быть асинхронный метод, который работает за пределами ngZone, тогда вы можете попробовать следующее:

person olsn    schedule 19.12.2016
comment
Прежде всего, я ценю ваши усилия, спасибо. Я пробую все, что вы написали. Вы правы насчет наблюдаемого внутри наблюдаемого. Я не предоставил весь код компонента, где я отписываюсь на ngOnDestroy. API чистый, и когда я console.log(temp) в сервисе, я получаю данные, которые мне нужны, но не в компоненте, где я получаю пустой массив. У меня нет ошибок в консоли, поэтому я понятия не имею, что делать, любой совет мне поможет. Я не знаю, не имеет ли это значения, но я амбициозно обновляю это приложение с rc6 до 4.0.0-beta.0, и все работает хорошо, кроме этого BehaviorSubject. - person Matej Maloča; 20.12.2016
comment
И я также пробую NgZone, но не уверен, что это правильный путь... проверьте редактирование основного сообщения... - person Matej Maloča; 20.12.2016
comment
Вам просто нужно обернуть вызовы .next в ngZone.run - это уже должно делать это, нет необходимости во многих слоях обратных вызовов и т. Д. :) - person olsn; 21.12.2016
comment
Все равно не работает. Я console.log(projects$) на какой-то случайной кнопке нажимаю, поэтому привожу скриншот. - person Matej Maloča; 21.12.2016
comment
Мне удалось заставить его работать, но мне нужно было ухудшить кучу пакетов, включая angular, до 2.1... до сих пор не понял, какой из них ломает его без ошибки.... - person Matej Maloča; 21.12.2016