Populating nativescript radList view with Data from Webservice

459 views Asked by At

I have a RadList view which am trying to populate with data from a web service. The data returned from the service is in JSON format. So am trying to create a service which i will use to get the information by passing the respective URL. Below are the codes:-

interface class (cps-admin.interface.ts)

export class AddTenantInterface {
        tenant_id: string;
        tenant_names: string;
        tenant_contact: string;
        tenant_email: string;
        starting_date: string;
        rent_amount: string;
        initial_water_reading: string;
        water_unit_cost: string;
    }

the service (CPSAdminService.ts)

    import { Injectable } from "@angular/core";
    import { AddTenantInterface } from "../interfaces/cps-admin.interface";
    import { Observable } from "rxjs";
    import { HttpClient, HttpHeaders, HttpResponse } from "@angular/common/http";

    @Injectable()
    export class CPSAdminService {

        public _fetchTenantListUrl: string = "http://192.168.137.1/cps/fetchTenantsObj.php"; // fetch tenants list api url

        constructor(private _http: HttpClient) {}       

       fetchTenantsList()  {

            let headers = this.createRequestHeader();
            return this._http.get(this._fetchTenantListUrl, { headers: headers });

        }        

        private createRequestHeader() {
            // set headers here e.g.
            let headers = new HttpHeaders({
                "AuthKey": "my-key",
                "AuthToken": "my-token",
                "Content-Type": "application/json",
             });

            return headers;
        }  

    }

Here is the tenants-component.ts

import { Component, OnInit, ChangeDetectorRef, ViewChild, ChangeDetectionStrategy} from "@angular/core";
import { AddTenantInterface } from "./../../interfaces/cps-admin.interface";
import { CPSAdminService } from "./../../services/cps-admin.service";
import * as ApplicationSettings from "application-settings";
import { ObservableArray } from "tns-core-modules/data/observable-array";
import { RadListViewComponent } from "nativescript-ui-listview/angular";
import { ListViewLinearLayout, ListViewEventData, RadListView, LoadOnDemandListViewEventData } from "nativescript-ui-listview";
import { setTimeout } from "tns-core-modules/timer";
import { TextField } from "ui/text-field";

@Component({
    selector: "tenants-list",
    moduleId: module.id,
    templateUrl: "./tenants-list.component.html",
    styleUrls: ["./tenants-list.css"]
})

export class TenantListComponent implements OnInit {

   public rentItems: ObservableArray<AddTenantInterface>; 
    private _sourceDataItems: ObservableArray<AddTenantInterface>;
    private layout: ListViewLinearLayout;

    public searchPaymentsList: string;
    private _myFilteringFunc: (item: any) => any;
    @ViewChild("myListView") myListViewComponent: RadListViewComponent;

    constructor(private _cPSAdminService: CPSAdminService,  private _changeDetectionRef: ChangeDetectorRef) {}

    ngOnInit(): void {        

        this.layout = new ListViewLinearLayout();
        this.layout.scrollDirection = "Vertical";
        this.initDataItems();
        this._changeDetectionRef.detectChanges();
        this.rentItems = new ObservableArray<AddTenantInterface>();
        this.addMoreItemsFromSource(6);

    }

    get myFilteringFunc(): (item: any) => any {
        return this._myFilteringFunc;
    }

    set myFilteringFunc(value: (item: any) => any) {
        this._myFilteringFunc = value;
    }


   public onTextChanged(args) {
        let searchBar = <TextField>args.object;
        let listView = this.myListViewComponent.listView;

          this.myFilteringFunc = (item: AddTenantInterface) => {
              return item.tenant_names.includes(searchBar.text) || item.starting_date.includes(searchBar.text);
          };

        if (!listView.filteringFunction) {
            listView.filteringFunction = this.myFilteringFunc;
        } else {
            listView.filteringFunction = undefined;
        }

    } 

    get rentDataItems(): ObservableArray<AddTenantInterface> {
        return this.rentItems;
    }

    public addMoreItemsFromSource(chunkSize: number) {
        let newItems = this._sourceDataItems.splice(0, chunkSize);
        this.rentDataItems.push(newItems);
    }


    public onLoadMoreItemsRequested(args: LoadOnDemandListViewEventData) {
        const that = new WeakRef(this);
        if (this._sourceDataItems.length > 0) {
            setTimeout(function () {
                const listView: RadListView = args.object;
                that.get().addMoreItemsFromSource(2);
                listView.notifyLoadOnDemandFinished();
            }, 1000);
        } else {
            args.returnValue = false;
        }
    }
// ===== **PROBLEM IS HERE**
    private initDataItems() {
        this._sourceDataItems = new ObservableArray(this._cPSAdminService.fetchTenantsList()); 
    }

}

Note where i have marked "PROBLEM IS HERE", Here is the error image clip I just don't what the problem. When i place "any" as the method return in fetchTenantsList() like so fetchTenantsList(): any , the error disappears but nothing is displayed in list. And when i hard code the data there like below, it works;

    tenantData: AddTenantInterface[] =     [
    {
        "tenant_id":"542948",
        "tenant_names":"Jane Doe",
        "tenant_contact":"0787916686",
        "tenant_email":"[email protected]",
        "starting_date":"2004-08-09",
        "rent_amount":"850000",
        "initial_water_reading":"100",
        "water_unit_cost":"250"
    },
    {
        "tenant_id":"575550",
        "tenant_names":"Emily Clarke",
        "tenant_contact":"07752654868",
        "tenant_email":"[email protected]",
        "starting_date":"2007-07-04",
        "rent_amount":"700000",
        "initial_water_reading":"400",
        "water_unit_cost":"250"
    },
    {
        "tenant_id":"422031",
        "tenant_names":"John Doe",
        "tenant_contact":"0772485364",
        "tenant_email":"[email protected]",
        "starting_date":"2008-12-14",
        "rent_amount":"700000",
        "initial_water_reading":"120",
        "water_unit_cost":"250"
    }
];
fetchTenantsList(): AddTenantInterface[] {
  return this.tenantData;
}

Here is my component html:

<GridLayout class="page page-content custom_font_family m-5" rows="50, *">      


    <StackLayout class="input-field" row="0">
        <TextField 
                   hint="search..." 
                   [(ngModel)]='searchPaymentsList' 
                   secure="false"
                   returnKeyType="done" 
                   (textChange)="onTextChanged($event)"
                   autocorrect="false"
                   autocapitalizationType="allCharacters"
                   focus="onFocus"
                   blur="onBlur"
                   class="input input-border" 
                   color="navy" 
                   textFieldHintColor="#bfbfbf"></TextField>
    </StackLayout>

    <GridLayout tkExampleTitle tkToggleNavButton row="1"  rows="*">

        <RadListView [items]="rentDataItems" loadOnDemandMode="Manual" (loadMoreDataRequested)="onLoadMoreItemsRequested($event)" [filteringFunction]="myFilteringFunc" #myListView row="0">
            <ng-template tkListItemTemplate let-item="item" let-i="index" let-odd="odd" let-even="even">

             <StackLayout [class.odd]="odd" [class.even]="even"  class="list-group-item p-y-10 m-y-2 t-17 p-x-5">

                  <Label [text]='item.starting_date | date: "d-M-y"'></Label>
                  <Label [text]='item.tenant_id + ". "'></Label>
                  <Label [text]='item.tenant_names'></Label>
                  <Label [text]='item.tenant_contact'></Label>
                  <Label [text]='item.tenant_email'></Label>
                  <Label [text]='item.rent_amount | currency:"UG ":"Ug. ": "3.1-1"'></Label>

                </StackLayout>

                <!--</GridLayout>-->
            </ng-template>
            <ng-template tkListViewHeader>

                <GridLayout class="header" rows="*" columns="30, auto, auto, auto, auto, auto">

                  <Label row="0" col="0" text='Date'></Label>
                  <Label row="0" col="1" text='No '></Label>
                  <Label row="0" col="2" text='Names'></Label>
                  <Label row="0" col="3" text='Contact'></Label>
                  <Label row="0" col="4" text='Email'></Label>
                  <Label row="0" col="5" text='Rent'></Label>

                </GridLayout>

            </ng-template>


            <ListViewLinearLayout *tkIfIOS tkListViewLayout itemHeight="120"></ListViewLinearLayout>

            <div *tkIfIOS>
                <GridLayout *tkListLoadOnDemandTemplate class="loadOnDemandItemGridLayout">
                    <Label text="Load More" horizontalAlignment="center" verticalAlignment="center"></Label>
                </GridLayout>
            </div>

        </RadListView>
    </GridLayout>

</GridLayout>

Any help is appreciated.

2

There are 2 answers

1
Manoj On BEST ANSWER

this._cPSAdminService.fetchTenantsList()

This will return an Observable that emits the result from server when the request is completed. You can't simply pass it to Observable Array.

It must be something like this,

this._cPSAdminService.fetchTenantsList()
      .subscribe((result) => {
           this._sourceDataItems = new ObservableArray(result);
      });
0
AudioBubble On

Alright my bad. I was supposed to remove this.addMoreItemsFromSource(6) from ngOnInit() and put it inside the subscribe. Here is the solution.

import { Component, OnInit, ChangeDetectorRef, ViewChild, ChangeDetectionStrategy} from "@angular/core";
import { AddTenantInterface } from "./../../interfaces/cps-admin.interface";
import { CPSAdminService } from "./../../services/cps-admin.service";
import * as ApplicationSettings from "application-settings";
import { ObservableArray } from "tns-core-modules/data/observable-array";
import { RadListViewComponent } from "nativescript-ui-listview/angular";
import { ListViewLinearLayout, ListViewEventData, RadListView, LoadOnDemandListViewEventData } from "nativescript-ui-listview";
import { setTimeout } from "tns-core-modules/timer";
import { TextField } from "ui/text-field";

@Component({
    selector: "tenants-list",
    moduleId: module.id,
    templateUrl: "./tenants-list.component.html",
    styleUrls: ["./tenants-list.css"]
})

export class TenantListComponent implements OnInit {

   public rentItems: ObservableArray<AddTenantInterface>; 
    private _sourceDataItems: ObservableArray<AddTenantInterface>;
    private layout: ListViewLinearLayout;

    public searchPaymentsList: string;
    private _myFilteringFunc: (item: any) => any;
    @ViewChild("myListView") myListViewComponent: RadListViewComponent;

    constructor(private _cPSAdminService: CPSAdminService,  private _changeDetectionRef: ChangeDetectorRef) {}

    ngOnInit(): void {        

        this.layout = new ListViewLinearLayout();
        this.layout.scrollDirection = "Vertical";
        this.initDataItems();
        this._changeDetectionRef.detectChanges();
        this.rentItems = new ObservableArray<AddTenantInterface>();
        //this.addMoreItemsFromSource(6); // remove this and put it inthe initDataItems method

    }

    get myFilteringFunc(): (item: any) => any {
        return this._myFilteringFunc;
    }

    set myFilteringFunc(value: (item: any) => any) {
        this._myFilteringFunc = value;
    }


   public onTextChanged(args) {
        let searchBar = <TextField>args.object;
        let listView = this.myListViewComponent.listView;

          this.myFilteringFunc = (item: AddTenantInterface) => {
              return item.tenant_names.includes(searchBar.text) || item.starting_date.includes(searchBar.text);
          };

        if (!listView.filteringFunction) {
            listView.filteringFunction = this.myFilteringFunc;
        } else {
            listView.filteringFunction = undefined;
        }

    } 

    get rentDataItems(): ObservableArray<AddTenantInterface> {
        return this.rentItems;
    }

    public addMoreItemsFromSource(chunkSize: number) {
        let newItems = this._sourceDataItems.splice(0, chunkSize);
        this.rentDataItems.push(newItems);
    }


    public onLoadMoreItemsRequested(args: LoadOnDemandListViewEventData) {
        const that = new WeakRef(this);
        if (this._sourceDataItems.length > 0) {
            setTimeout(function () {
                const listView: RadListView = args.object;
                that.get().addMoreItemsFromSource(2);
                listView.notifyLoadOnDemandFinished();
            }, 1000);
        } else {
            args.returnValue = false;
        }
    }
    public initDataItems() {
        //this._sourceDataItems = new ObservableArray(this._cPSAdminService.fetchTenantsList());  

        this._cPSAdminService.fetchTenantsList()
        .subscribe( (result) => {
            this._sourceDataItems = new ObservableArray(result);
            this.addMoreItemsFromSource(6); // put it here
        },
        error => {
            console.log("Error: ", error);
        });
    }

}

Thanks @Manoj