This is a migrated thread and some comments may be shown as answers.

IOS - RadListView Fatal Javascript exception

2 Answers 125 Views
ListView
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Anurag
Top achievements
Rank 1
Anurag asked on 12 Sep 2017, 07:43 AM

In my NativeScript angular project I am using a radlistview to display a list of messages from a firebase backend.  In Android the list item is displaying correctly however in IOS I am getting the following error and the application is terminated:

CONSOLE WARN file:///app/tns_modules/tns-core-modules/application/application.js:212:26: Fatal JavaScript exception - application has been terminated.
file:///app/tns_modules/nativescript-telerik-ui/listview/listview.js:1311:20: JS ERROR TypeError: undefined is not an object (evaluating 'type.toLowerCase')

 

I am using the latest version of the nativescript-telerik-ui 3.1.0 and tns 3.2.

My code for the template, component and service is as follows, Please let me know what I  need to change.  

Component.html 

<GridLayout rows="*" class="m-x-10">
        <RadListView [items]="this.messagesForView" [itemTemplateSelector]="templateSelector">
            <ng-template tkTemplateKey="testPrint" let-item="item">
                <!--For testPrint messages-->
                <GridLayout rows="auto auto" columns="auto *">
                    <Label row="0" col="0" text="" class="fa p-t-4 m-y-5"></Label>
                    <Label row="0" col="1" [text]="'Your item ' + item.testName + 'is ready for download at ' + item.testLink"></Label>
                    <Label row="1" col="1" text="11:50" horizontalAlignment="right"></Label>
                </GridLayout>
            </ng-template>
            <ng-template tkTemplateKey="otherMessage" let-item="item">
                <!--For Other Messages-->
                <GridLayout rows="auto auto" columns="auto *">
                    <Label row="0" col="0" text="" class="fa p-t-4 m-y-5"></Label>
                    <Label row="0" col="1" [text]="item.body"></Label>
                    <Label row="1" col="1" text="13:10" horizontalAlignment="right"></Label>
                </GridLayout>
            </ng-template>
        </RadListView>
    </GridLayout>

 

Component.ts

import { AfterContentInit, Component, OnInit, OnDestroy } from "@angular/core";
import { NavigationExtras, Router } from "@angular/router";
import { RouterExtensions } from "nativescript-angular";
import { android } from "application"; // THis is to import application for handleing back button.
 
import { Subscription } from "rxjs/Rx";
import { Page } from "ui/page";
import { Location } from "@angular/common";
 
//import ui elements
import scrollViewModule = require("ui/scroll-view");
// import htmlViewModule = require("ui/html-view");
import { ListViewEventData, RadListView } from "nativescript-telerik-ui/listview"; //This import is for rad list and event data on radList.
import { topmost } from "ui/frame"; //To catch the rad list component as view.
import { View } from "ui/core/view"; //To use a component as a View.
 
import { isTablet } from "../shared/device-constant/device.constant";
 
import { UserStatusService } from "../services/userStatus.service";
import { FirebaseMessagingService } from "../services/firebase-messaging.service";
 
import { AndroidBAckButtonHandlerService } from "../services/androidBackButtonHandler.service";
import { ObservableArray } from "data/observable-array";
 
@Component({
    moduleId: module.id,
    selector: "messaging",
    styleUrls: [(isTablet ? '../tablet.css' : '../phone.css')],
    templateUrl: "./messaging.component.html",
})
 
export class MessagingComponent implements OnInit, OnDestroy {
 
    uid: string;
    private backButtonHandler: Subscription;
    public isTablet: boolean;
    public messagesForView: ObservableArray<any>;
    private _templateSelector: (item: any, index: number, items: any) => string;
    public messagesSubscriber: Subscription;
 
    constructor(private router: Router,
        private routerExtensions: RouterExtensions,
        private location: Location,
        private userStatusService: UserStatusService,
        private firebaseMessagingService: FirebaseMessagingService,
        private page: Page,
        private androidBAckButtonHandlerService: AndroidBAckButtonHandlerService) {
 
    }
 
    public ngOnInit() {
        this.messagesForView = new ObservableArray();
        this._templateSelector = this.templateSelectorFunction;
        this.page.actionBarHidden = true;
        this.messagesSubscriber = this.firebaseMessagingService.messagesReceived.subscribe((currentMessages) => {
            this.messagesForView.push.apply(this.messagesForView, currentMessages);
        });
        this.firebaseMessagingService.getMessageFromFirebase();
        if (this.firebaseMessagingService.getMessages() !== undefined) {
            this.messagesForView = JSON.parse(this.firebaseMessagingService.getMessages());
        } else {
            const welcomeMessage = {
                type: "otherMessage",
                testName: "Trial Test",
                testLink: "Trial Link",
                title: "Welcome",
                body: "Hello",
            };
            this.messagesForView.push(welcomeMessage);
        }
       
        //Subscribing android back button event emitter.
        this.backButtonHandler = this.androidBAckButtonHandlerService.detailTestBackHandler.subscribe((status) => {
            console.log("Back button pressed on detail test component and the status is: " + JSON.stringify(status));
 
        });
 
    }
 
    get dataItems(): ObservableArray<any> {
        return this.messagesForView;
    }
 
    get templateSelector(): (item: any, index: number, items: any) => string {
        return this._templateSelector;
    }
 
    set templateSelector(value: (item: any, index: number, items: any) => string) {
        this._templateSelector = value;
    }
 
    public templateSelectorFunction = (item: any, index: number, items: any) => {
        return item.messageType;
    }
 
 
    public ngOnDestroy() {
        if (android) {
            this.backButtonHandler.unsubscribe();
            console.log("Back button handler is unsubscribed !!");
        }
    }
 
}

 

Service.ts 

import { Injectable, EventEmitter, NgZone } from "@angular/core";
import firebase = require("nativescript-plugin-firebase");
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import 'rxjs/add/operator/share';
import { setString, getString, remove } from "application-settings";
import { ObservableArray } from "tns-core-modules/data/observable-array";
 
@Injectable()
export class FirebaseMessagingService {
    public messagesReceived: BehaviorSubject<any> = new BehaviorSubject({});
 
    constructor(
        private ngZone: NgZone,
    ) {
    }
 
    // Get the User's messages
    public getMessageFromFirebase(): void {
        console.log("I have come to get my messages");
        firebase.addOnMessageReceivedCallback(
            (message) => {
                if (message) {
                    //create message object
                    let currentMessages = new ObservableArray();
                    const newMessage = this.createMessageObject(message);
                    if (this.getMessages() !== undefined) {
                        currentMessages.push.apply(currentMessages, JSON.parse(this.getMessages()));
                    }
                    console.log("Current Messages is " + currentMessages);
                    currentMessages.push(newMessage);
                    console.log("After pushing Current Messages is " + currentMessages);
                    this.setMessages(JSON.stringify(currentMessages));
                    this.messagesReceived.next(currentMessages);
                }
            },
        );
    }
 
    createMessageObject(message) {
        console.log("Message Data type is" + message.type);
        console.log("Type of the message type is" + typeof (message.type));
        if (message.type === "testPrint") {
            const messageObject = {
                messageTestName: message.title,
                messageType: message.type,
                messageBody: message.body,
                messageTestLink: message.testLink,
            };
            return messageObject;
        }
        else {
            const messageObject = {
                messageTitle: message.title,
                messageType: message.type,
                messageBody: message.body,
            };
            return messageObject;
        }
    }
 
    setMessages(storedMessages: string) {
        setString('storedMessages', (storedMessages));
    }
 
    getMessages() {
        return getString('storedMessages');
    }
 
    removeMessages() {
        remove('storedMessages');
    }
 
}

 

Thank you.

2 Answers, 1 is accepted

Sort by
0
Accepted
Deyan
Telerik team
answered on 12 Sep 2017, 07:50 AM
Hi Anurag,

Thanks for writing.

I think the reason for this error is that in your template selector you are returning `undefined` as a value for the template type:

public templateSelectorFunction = (item: any, index: number, items: any) => {
        return item.messageType;
    }

I see from  your code that the property representing the template type is called `type` not `messageType`.

I hope this is helpful.

Regards,
Deyan
Progress Telerik
Did you know that you can open private support tickets which are reviewed and answered within 24h by the same team who built the components? This is available in our UI for NativeScript Pro + Support offering.
0
Anurag
Top achievements
Rank 1
answered on 12 Sep 2017, 07:56 AM
Many Thanks Deyan! That was indeed the problem
Tags
ListView
Asked by
Anurag
Top achievements
Rank 1
Answers by
Deyan
Telerik team
Anurag
Top achievements
Rank 1
Share this question
or