异步调用通过Angular 4.x服务更新HTML元素

时间:2017-04-23 13:10:31

标签: angular typescript rxjs

尝试在组件之间更新HTML元素使用角度服务似乎对我不起作用。

这不是How do I return the response from an asynchronous call?的重复。

完整项目:https://github.com/flamusdiu/micro-blog/tree/dev

我有这项服务:

import { ElementRef, Injectable } from '@angular/core';
import { MdSidenav } from '@angular/material';
import { AsyncSubject } from 'rxjs/AsyncSubject ';

import { Article } from '../models/article';

@Injectable ()
export class InterModuleService {
    private _article: AsyncSubject <Article> = new AsyncSubject();      
    public sidenav: MdSidenav;
    public sidenavToc: ElementRef;
}

我把我的观察放在这里。通过Angular Resolver为我的路线填充可观测量。该组件设置为:

import { Component, Input, OnInit } from '@angular/core';
import { ActivatedRoute }   from '@angular/router';

import { Article } from '../../models/article';
import { InterModuleService } from '../../service/inter-module.service';

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

  private article: Article;

  constructor( private route: ActivatedRoute, private interModuleService: InterModuleService ) { }

  ngOnInit(): void {
    this.route.data
        .subscribe((data: { article: Article } ) => {
            this.interModuleService.article.next(data.article);
        });

    this.interModuleService.article
        .subscribe((data) => {
            this.article = data;
            this.interModuleService.sidenavToc.nativeElement['innerHTML'] = data.toc;
        });
  }
}

我得到的是某种异步问题。我得到了更新视图的文章数据。但是,文章对象的任何属性在任何时候读取都是“未定义”或“空”,这使得我尝试这样做的方法并不完全正确。

如果我添加一些这样的console.log:

this.interModuleService.article.take(1)
        .subscribe((data) => {
            this.article = data;
            console.log(this.article);
            console.log(this.article.toc);
            this.interModuleService.sidenavToc.nativeElement['innerHTML'] = data.toc;
        });

我得到以下截图(忽略HTML格式问题):

screencap of issue

仅供参考:article.tocarticle.attachments['toc']['data']的简写。但是,直接引用它会产生与上面相同的结果。 article.attachments['toc']有数据,但调用时属性data未定义。

BehaviorSubject更改为AsyncSubject,因为我只关心最后发出的一个。可能不应该暴露主题,但没有看到不这样做的好方法。虽然data.toc仍未定义。 =(

1 个答案:

答案 0 :(得分:0)

由于某些原因,我不得不移动整个异步过程,使附件更接近我需要它的位置。我仍然不确定这样做的原因,然后与Async进程解决的方式有关,并期望可能在任何点上出现的值都需要考虑。

以下是工作代码:

<强>间module.service.ts

import { ElementRef, Injectable } from '@angular/core';
import { MdSidenav } from '@angular/material';
import { AsyncSubject } from 'rxjs/AsyncSubject';

import { Article } from '../models/article';

@Injectable ()
export class InterModuleService {
    public article: AsyncSubject<Article> = new AsyncSubject();

    public sidenav: MdSidenav;
    public sidenavToc: ElementRef;  
}

<强>物品detail.component.ts

import { Component, Input, OnInit } from '@angular/core';
import { ActivatedRoute }   from '@angular/router';

import { Article } from '../../models/article';

import { ArticleStore } from '../../state/ArticleStore';
import { InterModuleService } from '../../service/inter-module.service';

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

  private article: Article;

  constructor( private route: ActivatedRoute, 
               private articleStore: ArticleStore,
               private interModuleService: InterModuleService ) { }

  ngOnInit(): void {
    this.interModuleService.article
        .subscribe((data) => {
            this.article = data;

            Promise.all(Object.keys(this.article['attachments']).map((at) => {
                return this.articleStore.getAttachment(this.article['id'],at).then ((res) => {
                    this.article.attachments[at]['data'] = res.toString();
                })
            })).then(()=> {
                this.interModuleService.sidenavToc.nativeElement['innerHTML'] = this.article.attachments['toc'].data;
            });

        });
    this.route.data
        .subscribe((data: { article: Article } ) => {
            this.interModuleService.article.next(data.article);
            this.interModuleService.article.complete();
        });
  }
}

<强>物品detail.resolver.ts

import { Injectable } from '@angular/core';
import { Router, Resolve, RouterStateSnapshot, ActivatedRouteSnapshot } from '@angular/router';
import { Article } from '../../models/article';
import { ArticleStore } from '../../state/ArticleStore';


@Injectable()
export class ArticleDetailResolver implements Resolve<Article> {

  constructor(private articleStore: ArticleStore, private router: Router) {}

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<Article> {

    let id = route.params['id'];

    return this.articleStore.getArticle(id).then(article => {
      if (article) {
        return new Article(article);

      } else { // id not found
        this.router.navigate(['/articles']);
        return null;
      }
    });
  }
}