How to access the object in the observable list

懵懂的女人 提交于 2021-02-11 04:53:48

问题


I'm building a quiz app. My idea is to show 1 question per page. How do I subscribe and get an object inside a list using Observable.

Instead of using *ngFor which display all of my objects. Is there a way to access the object one by one inside the subscribe block.

export class ExerciseFlashcardPage {


  questions: Observable < any > ;
  type: string;

  constructor(
    public navCtrl: NavController, 
    public navParams: NavParams, 
    public afd: AngularFireDatabase
  ) {
    this.type = this.navParams.get('data');
    this.questions = this.afd.list('exercises/' + this.type).valueChanges();
    this.questions.subscribe(e => {
      console.log(e); // how to access the data //only returns an array of object
    })

  }
}

And here's the Template:

<ion-header>
  <ion-navbar>
    <ion-title>exercise-flashcard</ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <ion-list>
    <ion-item *ngFor="let item of questions | async">
      {{item.question}}
    </ion-item>
  </ion-list>
</ion-content>

回答1:


First up, there's an issue with your implementation:

In your ExerciseFlashcardPage, you're subscribing to the Observable which will unwrap it. But then you're also using the async pipe in your template which will be expecting a Promise or an Observable.

Just remove the subscription line from your code:

// Remove this part
this.questions.subscribe(e => {
  console.log(e); // how to access the data //only returns an array of object
});

That way you also won't have to worry about manually unsubscribing from the subscription when this component is destroyed.

SOLUTION:

Now for your specific use-case, it doesn't matter how you handle the subscription. All you need is to show one question at a time. For that, you can just keep a currentQuestion property on your Component Class and then use *ngFor along with [ngClass]

And then when the user submits one question, you can increment the currentQuestion property by 1.

In code, this would look something like:

import { map } from 'rxjs/operators';

export class ExerciseFlashcardPage {

  questions: Observable < any > ;
  type: string;

  constructor(
    public navCtrl: NavController, 
    public navParams: NavParams, 
    public afd: AngularFireDatabase
  ) { }
  

  ngOnInit() {
    this.type = this.navParams.get('data');
    this.questions = this.afd.list('exercises/' + this.type).valueChanges()
      // The below Pipe operation is not required if you don't plan to change the data-model of the question object.
      .pipe(map(questions => {
        return questions.map(question => {
          return {
            ...question,
            yourNewKeyHere: 'Value to that new key here'
          }
        });
      }));
  }

  submitCurrentQuestion() {
    // Make changes to save the answer
    
    ++this.currentQuestion;
  }

}

And in template:

<ion-header>
  <ion-navbar>
    <ion-title>exercise-flashcard</ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <ion-list>
    <ion-item 
      *ngFor="let item of questions | async; let i = index;" 
      [ngClass]="(i === currentQuestion) ? '': 'hide'">
      {{item.question}}
    </ion-item>
  </ion-list>
</ion-content>

CSS:

.hide {
  display: none;
}

Here's a Sample StackBlitz for your ref.




回答2:


.subscribe(arr => {
  arr.forEach(item => {
    console.log(item)
  })      
})

OR to change the items:

.subscribe(arr => {
  this.arr = arr.map(item => {
    item.something = 'somevalue'
    console.log(item)
    return item
  })      
})



回答3:


I assume you want to have the whole array and use only specific elements in various situations without having to subscribe again.

question: string;
questionsArray: Array<any>
elementToShow = 0; //whichever element you want to show

this.questions.subscribe(e => {
      questionsArray = e;
    });

With html:

<ion-list>
    <ion-item>
      {{questionsArray[elementToShow]}}

    </ion-item>
</ion-list>

If you really want to subscribe to one element of the array it would look like this:

question: string;
elementToShow = 0; //whichever element you want to show

this.questions.subscribe(e => {
      question = e[elementToShow];
    }

With html:

<ion-list>
    <ion-item>
      {{question}}

    </ion-item>
</ion-list>

Subscribing to Observables is async, so be aware that it will be displayed in the way you want only after the subscribe method ends. After subscribe is executed it will be updated. In such a simple example you dont have to worry much about this.



来源:https://stackoverflow.com/questions/52721230/how-to-access-the-object-in-the-observable-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!