Display data that has not been displayed

Here is what my dummy app does at the moment :

Click a button => get a random object and display its info.

What I am trying to do :

Click a button => get a random object that has not been displayed yet and display its info.

How could I do that without removing data ?

random-cards.html

<!--
  Generated template for the RandomCardsPage page.

  See http://ionicframework.com/docs/components/#navigation for more info on
  Ionic pages and navigation.
-->
<ion-header>

  <ion-navbar>
    <ion-title>random-cards</ion-title>
  </ion-navbar>

</ion-header>


<ion-content padding>
  <ion-grid>
    <ion-row>
      <ion-col>
<!--         <ion-list>
          <ion-item *ngFor="let card of cards">
            ({{card.id}}) {{card.question}} - {{card.answer}}

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

      </ion-col>
    </ion-row>
    <ion-row>
      <ion-col>

        <button ion-button (click)="getRandom()">Get Random</button>

      </ion-col>
    </ion-row>
    <ion-row>
      <ion-col>
        <ion-list>
          <ion-item *ngFor="let rc of randomCard">
            ({{rc.id}}) {{rc.question}} - {{rc.answer}} - {{rc.played}}
          </ion-item>
        </ion-list>
      </ion-col>
    </ion-row>
  </ion-grid>

</ion-content>

random-cards.ts

import {Component, OnInit} from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
import cards from '../../providers/data/cards';
import {Card} from "../../providers/Models/cards.interface";

/**
 * Generated class for the RandomCardsPage page.
 *
 * See https://ionicframework.com/docs/components/#navigation for more info on
 * Ionic pages and navigation.
 */

@Component({
  selector: 'page-random-cards',
  templateUrl: 'random-cards.html',
})

export class RandomCardsPage implements OnInit {
  cards: Card[];
  randomCard: Card[];

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

  ngOnInit() {
    this.cards = cards.cards;
  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad RandomCardsPage');
    console.log(this.cards);
  }

  getRandom() {
    let rd = Math.floor(Math.random() * this.cards.length);
    this.randomCard = [this.cards[rd]];
  }

}

cards.ts

export default
  {
    "cards": [
      {
        "id": "1",
        "question": "question 1",
        "answer": "reponse 1",
        "hint": "hint 1",
      },
      {
        "id": "2",
        "question": "question 2",
        "answer": "reponse 2",
        "hint": "hint 2",
      },
      {
        "id": "3",
        "question": "question 3",
        "answer": "reponse 3",
        "hint": "hint 3",
      }
    ]
  };

cards.interface.ts

export interface Card {
  id: string;
  question: string;
  answer: string;
  hint: string;
}

You could create an array in your component (or provider) and push the cards id to it when it gets displayed. Then only display a card if it’s id is not in the array.

A better solution I think would be to add a

displayed: boolean;

property to your interface.
Initialize it to false on init.
Set it to true once it’s displayed.
Also add another array to your component.

availableCards: Card[];
constructor() {
 this.availableCards = [];

In getRandom()

this.availableCards = this.cards.filter(card => !card.displayed);

Then pull from the available card deck.

Math.random...this.availableCards.length;
this.availableCards[rd];

This satisfies your requirements of only having access to cards that have not yet been displayed, while leaving the original data intact

hello,

when you don’t want a new array, then you could shuffled that array to get a random sorted array instead of using a random index.

From the shuffled array you can take card by card.

Best regards, anna-liebt

1 Like

Thank you for your answer. I also thought a boolean property could make it.
I am trying to implement your solution. But nothing happens when I click the button. I guess I am missing a point somewhere. Also, how can I change the value once it’s displayed ?

random-cards.ts

export class RandomCardsPage implements OnInit {
  cards: Card[];
  randomCard: Card[];
  availableCards: Card[];

  constructor(public navCtrl: NavController, public navParams: NavParams) {
    this.availableCards = [];
  }

  ngOnInit() {
    this.cards = cards.cards;
  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad RandomCardsPage');
    console.log(this.cards);
  }

  getRandom() {
    this.availableCards = this.cards.filter(card => !card.displayed);
    let rd = Math.floor(Math.random() * this.availableCards.length);
    this.availableCards[rd];
  }
}

cards.interface.ts

export interface Card {
  id: string;
  question: string;
  answer: string;
  hint: string;
  displayed: boolean;
}

Hey there. I wrote my reply in a hurry and was using shorthand, so don’t quote it verbatim!
just apply it to what you aleady had.
for example, where I wrote

this.availableCards[rd]

It should be

this.randomCard = this.availableCards[rd];

As you wrote it initially.

I would, in ngOnInit()
set all cards to displayd: false.

export class RandomCardsPage implements OnInit {
 cards: Card[];
 availableCards: Card[];
 randomCard: Card[] 
 // or should this be a single card? I can't tell. If so, randomCard: Card;

constructor() {
  this.cards = [];
  this.randomCard = [] //if it's supposed to be an array
  this.availableCards = [];
 }

ngOnInit() {
  this.cards = cards.cards;
  this.cards.map(card => card.displayed = false);
 }

getRandom() {
  this.availableCards = this.cards.filter(card => !card.displayed);
  let rd = Math.floor(Math.random() * this.availableCards.length);
  this.randomCard = this.availableCards[rd];
  this.cards.find(card => card.id === this.randomCard.id).displayed = true;
 }

}

Thx for the explanation. I am not sure, but I think randomCard shouldn’t be an array. If I understand your code, randomCard corresponds to the randomly chosen card among the available cards ? so it should be a one card.

I have this error : "Runtime Error. Error trying to diff ’ [object Object ]’. Only arrays and iterables are allowed."
Any idea ?

cards.ts

export default
  {
    "cards": [
      {
        "id": "1",
        "question": "question 1",
        "answer": "reponse 1",
        "hint": "hint 1",
        "displayed": "",
      },
      {
        "id": "2",
        "question": "question 2",
        "answer": "reponse 2",
        "hint": "hint 2",
        "displayed": "",
      },
      {
        "id": "3",
        "question": "question 3",
        "answer": "reponse 3",
        "hint": "hint 3",
        "displayed": "",
      }
    ]
  };

Yeah, that what I had in mind. That the random card was singular. I wasn’t 100% sure that was your plan based on the code you posted.

You’re getting the “trying to diff” error because you’re trying to make a list out of the singular random card, which is an object.

Is probably the cause of your problem. To get that working, you’ll have to use a different approach when displaying it.

Ok thx for your help. I will try to find a new way to display the data, I am going through a few errors.