首页 > 解决方案 > Rxjs 发现运算符不能处理 Observable 数组中的值

问题描述

我有一个服务,我将我的 http 有效负载投射到一个 Observable 数组,我希望能够调用该服务中的一个方法来对该 observable 采取行动。在我的情况下,我想确认一个 ID 存在于 Observable ID 的数组中。我已经对 stackoverflow 进行了一些研究,我认为这是因为我错误地处理了 find 运算符的返回(据我所知,它返回一个 observable)。

服务 :

@Injectable({
  providedIn: 'root'
})
export class RuleFieldsService {
  baseUrl: string;
  relativeUrl: string;
  httpOptions = {
    headers: new HttpHeaders({
      'Content-Type': 'application/json'
    })
  };
  private rulefieldIdSub = new BehaviorSubject<any[]>([]);
  private rulefieldIdStore: { ruleFieldIds: any } = { ruleFieldIds: [] };
  rulefieldIds$ = this.rulefieldIdSub.asObservable();


  constructor(private readonly http: HttpClient, @Inject(APP_BASE_HREF) 
              private readonly baseHref: string) 
              {
                this.baseUrl = this.baseHref + environment.baseAPIUrl;
               };

  getRuleFields() {
    this.relativeUrl = 'rulefields';
    return this.http.get(this.baseUrl + this.relativeUrl);
  }


  getList(){
    
    this.relativeUrl = 'rulefields';

    this.http.get(this.baseUrl + this.relativeUrl + '/enabledropdown').subscribe(data => {
      this.rulefieldIdStore.ruleFieldIds = data;
      this.rulefieldIdSub.next(Object.assign({}, this.rulefieldIdStore).ruleFieldIds);
    });
  }

  checkRuleFieldType(ruleFieldId) {
    console.log('check method')
    this.rulefieldIds$.pipe(find((id: any) => id === ruleFieldId)).subscribe(items => {
        console.log("ID is in the list")
    });
  }      
}

零件 :

@Component({
  selector: 'app-rules-tab-wrapper',
  templateUrl: './rules-tab-wrapper.component.html',
  styleUrls: ['./rules-tab-wrapper.component.scss']
})
export class RulesTabWrapperComponent implements OnInit {
public selectedIndex;
public ruleFieldIds$: Observable<any[]>;
  constructor(private rulesetService: RulesetService,
              private rulefieldService: RuleFieldsService) { }

  ngOnInit() {

    this.rulefieldService.getList();
     this.ruleFieldIds$ = this.rulefieldService.rulefieldIds$;
     this.rulefieldService.checkRuleFieldType(15);
     console.log(this.ruleFieldIds$ )
  }
}

我查看了 Observable 以尝试更好地了解错误可能在哪里,但我无法对信息做出可操作的意义:

source: BehaviorSubject
 closed: false
 hasError: false
 isStopped: false
 observers: Array(1)
  0: FindValueSubscriber
   closed: false
   destination: Subscriber {closed: false, _parentOrParents: null, _subscriptions: Array(1), syncErrorValue: null, syncErrorThrown: false, …}
   index: 2
   isStopped: false
   predicate: (id) => id === ruleFieldId
   source: Observable
   source: BehaviorSubject {_isScalar: false, observers: Array(1), closed: false, isStopped: false, hasError: false, …}
   _isScalar: false
   __proto__: Object
syncErrorThrowable: true
syncErrorThrown: false
syncErrorValue: null
thisArg: undefined
yieldIndex: false
  _parentOrParents: Subscriber
  closed: false
  destination: SafeSubscriber {closed: false, _parentOrParents: null, _subscriptions: null, syncErrorValue: null, syncErrorThrown: false, …}
  isStopped: false
  syncErrorThrowable: true
  syncErrorThrown: false
  syncErrorValue: null
  _parentOrParents: null
  _subscriptions: [FindValueSubscriber]
  __proto__: Subscription
_subscriptions: [SubjectSubscription]
__proto__: Subscriber
length: 1
__proto__: Array(0)
thrownError: null
_isScalar: false
_value:
 enableDropdownFor: (6) [15, 42, 55, 65, 67, 69]

提前感谢您的洞察力!

标签: angularrxjs

解决方案


您正在了解“查找”运算符如何有点偏离。它是一个过滤器,旨在过滤发出多个值的数据流,但在值与谓词匹配然后停止发出之前不会发出任何内容。

https://rxjs-dev.firebaseapp.com/api/operators/find

您的示例 observable 发出一个值,恰好是一个数组。您想要在函数中执行的操作是使用 rxjs 映射运算符,在其中您将拥有值数组,并使用标准数组的 find(或 findIndex),并返回一个布尔值。

我整理了一些堆栈闪电战来演示它,并附有一些评论。https://stackblitz.com/edit/angular-dra5wu?file=src%2Fapp%2Fapp.component.html

以下是我提到的一些概念和运算符:

export class ExampleService {
  // start with "null" so we can filter that out, this way we know our get list has ran at least once if that's important
  private rulefieldIdSub = new BehaviorSubject<any[]>(null);
  
  // we skip the intial "null" value, this makes sure "getList" has populated the rules
  rulefieldIds$ = this.rulefieldIdSub.asObservable().pipe(filter(ids => ids !== null));

  getList(){
    // making a fake list for example purposes, running in a set timeout so it takes a second
    setTimeout(() => {
      this.rulefieldIdSub.next([1,3,5,7,9])
    }, 1000);
  }

  checkRuleFieldType(ruleFieldId): Observable<boolean> {
    return this.rulefieldIds$.pipe(
      // we're using the "map" operator to transform the result from the observable into something else
      // https://rxjs-dev.firebaseapp.com/api/operators/map
      map(ruleFieldIds => {
        // map gets the full array of your ruleField ids, now we return if we found that id or not
        return ruleFieldIds.findIndex(id => id === ruleFieldId) !== -1;
      })
    )
      
  }    
 
}

以及使用它的更新组件

export class AppComponent  {
  name = 'Angular';
  rulefieldIds$: Observable<any[]>;

  constructor(public exampleService: ExampleService) {
    this.exampleService.getList();
    this.rulefieldIds$ = this.exampleService.rulefieldIds$;

    this.exampleService.checkRuleFieldType(15).subscribe(result => {
      console.log("Do we have 15?", result)
    });

    this.exampleService.checkRuleFieldType(5).subscribe(result => {
      console.log("Do we have 5?", result)
    });
  }
}

推荐阅读