Dynamically change contents of an ion-card


#1

Hi,

I have a list of books which are fetched to the class through a provider from the backend API. This is the sample data that I’m getting

 {
   "success":true,
   "books":[
      {
         "id":1000,
         "book_code":"CC219102",
         "read_status":"completed",
         "name":"Book A",
         "price":"80"
      },
      {
         "id":1001,
         "book_code":"CC219103",
         "read_status":"reading",
         "name":"Book B",
         "price":"50"
      },
      {
         "id":1002,
         "book_code":"CC219104",
         "read_status":"completed",
         "name":"Book C",
         "price":"120"
      },
      {
         "id":1003,
         "book_code":"CC219105",
         "read_status":"yet_to_read",
         "name":"Book D",
         "price":"75"
      },
      {
         "id":1004,
         "book_code":"CC219106",
         "read_status":"completed",
         "name":"Book E",
         "price":"100"
      }
   ]
}

As you can see, API retuns five books in this case. I’m calling a function loadBooks() inside the controller to fetch this data and it is stored in an array myBooks: any = [];

I iterate this array and display each book using an ionic card.

Things is, data we obtained might change. And there is another function refreshBookData() which fetched the data again and this has been implemented using a socket. So when changes are there, I wanna show the changes in the html page as well

If the price of a book changes, the new price will be available in this function and I want to update the card info for that book

In the web, it can be achieved easily. Don’t know how this can be achieved in ionic. Can anyone provide me with a solution?

HTML CODE

  <ion-card *ngFor="let book of books" id="{{book.book_code}}">
    <ion-grid>
      <ion-row class="{{book.read_status}} row">
        <ion-col>
            <span>{{book.name | uppercase}}</span>          
        </ion-col>
        <ion-col>
          <div>
            <div float-right>{{book.price}}</div>
          </div>
        </ion-col>
      </ion-row>
    </ion-grid>
  </ion-card>

And the component class looks like this:

import { Component } from '@angular/core';
import { NavController, NavParams, LoadingController } from 'ionic-angular';
import * as io from "socket.io-client";
import { BookServicesProvider } from './../../providers/book-services/book-services';
import { Storage } from '@ionic/storage';


@Component({
  selector: 'page-my-books-page',
  templateUrl: 'my-books-page.html',
})
export class MyJobsPage {
  memberId: any= 1;
  myBooks: any = [];

  constructor(public navCtrl: NavController, public navParams: NavParams,
    private storage: Storage, private bookService: BookServicesProvider) {
    this.loadBooks(this.memberId);
    this.refreshBookData(this.memberId);
  }

  loadBooks(memberId) {
    let reqParams = {
      memberId: memberId
    };
    this.jobService.myJobs(reqParams)
    .then(data => {
        this.myJobs = data['jobs'];
    });
  }

  refreshBookData(memberId) {
    var params = {
        memberId: memberId.toString()
    };
    var socket = io('localhost:3000/books');
    socket.on('connect', function (obj) {

        //Emitting the params to socket
        socket.emit('bookStatuses', params);

        socket.on('book_statuses', function (data) {
            //received data; storing it in temp variable
            var myBooksTemp = data.books;

            if (myBooksTemp) {
                //iterating through the changed data
                myBooksTemp.forEach((value, key, index) => {


                    //code to change html here

                    
                });
            }
        });
    });
  }
}

#2

You don’t have to change your html code.

Normally angular changes the view when you change the array in your code.


#3

So I gotta just change the array, right?

Okay, this is what I tried for that.
When I call loadBooks() initially, all book data is saved into myBooks: any = [];
And I iterate this to show list of books.

And when the socket function refreshBookData() is called, (which has changes to the data in the above array), I temporarily save it to a variable myBooksTemp

Inside refreshBookData(), I did this so I can get the index of each item in myBooks using the id from the temporary array.

myBooksTemp.forEach((value, key, index) => {
   let newVal= this.myBooks.find(x => x.job_code == value.job_code);
 });

But I’m getting the following error

ERROR TypeError: Cannot read property ‘find’ of undefined


#4

Change

var myBooksTemp = data.books;

to

this.myBooks = data.books;

in your

socket.on(‘book_statuses’, function (data) function.

Nothing more to do.


#5

data.books inside socket.on is refreshed book details. It has only book_code. Using that book_code, I need to identify the real object representing that book in this.myJobs


#6

Ah ok you get just an sub array.

So I woud try somthing like this ( send from my mobile phone so do not copy paste :slight_smile: )

this.myBooks.forEach((book, index) => { 
    myBooksTemp.forEach((tmpBook) => {
         if (book.book_code === tmpBook.book_code) {
            this.myBooks[index] = tmpBook
        }
    })   
});

Better make the tmpBook the outer forEach end this.myBooks the inner.