首页 文章

如何使用angular2链接rxjs Observable操作?

提问于
浏览
0

我有一个组件从服务获取数据:

ngOnInit(): void
    {
        this.categoryService.getCategories().subscribe((data) => {
               this.categories=data;

            }
        )
    }

这是服务代码:

getCategories(){
       return this.category.find({where: {clientId: this.userApi.getCurrentId()}}).map((data) => {
        return data;
        }, err => {
            console.log(err);
        });
    };

返回的数据结构是:

{"categoryName":"Google","id":"58591d2b7672d99910497bec","clientId":"585808f6737f6aad1985eab2"},{"categoryName":"Yahoo","id":"58591d4c7672d99910497bef","clientId":"585808f6737f6aad1985eab2"},{"categoryName":"Msn","id":"585d25f6ae4b2ecb056bc514","clientId":"585808f6737f6aad1985eab2"}

我在 this.categories 上有另一种叫做 countLinks(id) 的方法; id 是一个类别参数,如 585d25f6ae4b2ecb056bc514 ,取自数据结构 .

countLinks() 返回包含该特定类别的所有链接的observable .

我想在我的数据结构中添加另一个属性,其中包含每个类别ID的链接数量 . 就像是 :

{"categoryName":"Google","id":"58591d2b7672d99910497bec",**"nblinks":"0"**,"clientId":"585808f6737f6aad1985eab2"},
{"categoryName":"Yahoo","id":"58591d4c7672d99910497bef",**"nblinks":"5"**,"clientId":"585808f6737f6aad1985eab2"},
{"categoryName":"Msn","id":"585d25f6ae4b2ecb056bc514",**"nblinks":"12"**,"clientId":"585808f6737f6aad1985eab2"}

要添加信息,类别是数组类型:
Preview data structure with Augury

任何的想法?

3 回答

  • 2

    您描述的是mergeMap()运算符的典型用例 .

    试试这段代码:

    getCategories() {
      return this.category.find({where: {clientId: ID}})
        .mergeMap(category =>
          countLinks(category.id).map(categoryLinks => {
            return Object.assign({}, category, { nblinks: categoryLinks.length })
          })
        );
    };
    

    我将第一个observable(由 this.category.find() 返回)映射到另一个observable(由 countLinks() 返回) .

    在最里面的 map() 中,我最终得到了 categorycategoryLinks ,并将它们合并为一个带有 Object.assign() 的单个对象 .


    附注:您的原始代码有点令人困惑 . 你写了"I have another method on this.categories called countLinks(id)"但你也写了 this.categories=data . 你怎么能在数据结构上有一个方法?我在假设 this.category.find()countLinks() 返回observables的情况下写了我的答案,但是你必须根据你的特定代码/情况调整我的解决方案 .

  • 2

    首先,你正在做的是可怕的做法 . 以下是我如何分解您的问题:

    • 从后端获取对象列表 .

    • 从后端获取每个对象的附加属性,每个对象调用一次 .

    如果要为两个呼叫命中相同的后端,则需要编写 endpoints 以获取所需的所有数据,即句点 . 如果要打两个后端,则需要传递一个clientIds数组并在一次调用中获取链接数 . 如果您不控制第二个呼叫后端,那么很好,让我们像步骤1和2中的大纲一样 .

    您的结构需要如下所示:

    • Observable获取数据(你有这个) . 仅将此映射到ID的函数 .

    • 从每个接收到的Id创建可观察对象的函数

    • A .forkJoin 可观察以进行所有个人通话 - 如果你熟悉的话,这就像Q.all一样 .

    我懒得为你编写完整的代码,抱歉,但基本上,当你获得数据时,你需要创建一个Observable for EACH值,如下所示:

    //This function will generate observables for you, when passed a param
    function generateMockLinkCallObs(clientId){
    
      var mockLinksCall = new Rx.Observable(observer => {
        var mockCallTime = Math.floor(Math.random() * 5000) + 1000; 
        setTimeout(() => {
          var mockLinks = Math.floor(Math.random() * 12) + 1;  
          observer.next(mockLinks); 
        }, mockCallTime)
      })
      return mockLinksCall; 
    
    }
    
    //This just uses the function above to generate your observables for EACH object 
    generateListOfObservableCalls(ids){
      var obsArray = [];
      var obs;
      ids.forEach(id => {
        obs = generateMockLinkCallObs(id);
        obsArray.push(obs);
      })
    
      return obsArray; 
    }
    
    //This just uses the above function. 
    getNumberOfLinks(data){
      var ids = data.map(data => data.id)
      var observables = generateListOfObservableCalls(ids);
      return observables; 
    }
    

    所以,要把它们放在一起,你得到你的初始数据:

    httpWhatever.subscribe(
      next => {
    
      var observablesForIndividualCalls = getNumberOfLinks(next); 
    
      Observable.forkJoin(observablesForIndividualCalls)
       .subscribe((response) => {
          console.log(response[0], response[1]);
       });
    
      }
    )
    

    我过度简化了最后一步,但forkJoin只有在你获得所有个人电话的结果后才能完成 .

    不,我不知道一个更简单的方法,虽然它绝对可以更清洁 .

  • 0

    创建两个接口 . 一个代表类别的基础,另一个代表它 .

    interface ICategory {
        categoryName: string;
        id: string;
        clientId: string;
    }
    
    interface ICategoryExpanded extends ICategory {
        nbLinks: string;
    }
    

    然后使用RxJS中的.map()运算符将数据转换为第二个接口 .

    this.getCategories().map((cats: ICategory[]) => {
                    let mapCategories: ICategoryExpanded[] = [];
                    cats.forEach((cat: ICategory) => {
                        let transformCat: ICategoryExpanded = <ICategoryExpanded>cat;
                        transformCat.nbLinks = this.countLinks(transformCat.id);
                        mapCategories = [...mapCategories, transformCat];
                    });
                    return mapCategories;
                })
                .subscribe((returnCategoriesExt) => this.categories = returnCategoriesExt);
    

    那应该处理你想要的东西并返回这样的东西:

    [{ "categoryName": "Google", "id": "58591d2b7672d99910497bec", "clientId": "585808f6737f6aad1985eab2", "nbLinks": "5" }, 
    { "categoryName": "Yahoo", "id": "58591d4c7672d99910497bef", "clientId": "585808f6737f6aad1985eab2", "nbLinks": "5" }, 
    { "categoryName": "Msn", "id": "585d25f6ae4b2ecb056bc514", "clientId": "585808f6737f6aad1985eab2", "nbLinks": "5" }]
    

相关问题