IOS - RadListView Fatal Javascript exception

3 posts, 1 answers
  1. Anurag
    Anurag avatar
    33 posts
    Member since:
    Apr 2016

    Posted 12 Sep Link to this post

    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. Answer
    Deyan
    Admin
    Deyan avatar
    2147 posts

    Posted 12 Sep Link to this post

    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.
  3. Anurag
    Anurag avatar
    33 posts
    Member since:
    Apr 2016

    Posted 12 Sep Link to this post

    Many Thanks Deyan! That was indeed the problem
Back to Top