Search code examples
angularangular2-nativescript

Angular2/Nativescript: Issues converting a service that used to use LocalStorage to one that uses nativescript-application/settings


I am busy with a simple barcode scanner app and trying to convert a service which used LocalStorage in a web app before to use application-settings to save a local IP. The app builds fine but when it gets deployed to a genymotion emulator I get the following error. Any idea why this might be happening? So it seems like the issue is with the getString and/or setString methods of application-settings. I coppyed a service from a web app which used LocalStorage and replaced localStorage with appSettings and getItem with getString and setString... Am i missing something in Nativescript's getString and setString? I thought it works the exact same way as the LocalStorage browser API...

my error:

JS: EXCEPTION: Error in ./AppComponent class AppComponent_Host - inline template:0:0 caused by: Unexpected token u in JSON at position 0
JS: ORIGINAL EXCEPTION: Unexpected token u in JSON at position 0
JS: ORIGINAL STACKTRACE:
JS: SyntaxError: Unexpected token u in JSON at position 0
JS:     at Object.parse (native)
JS:     at AppSettingsService.findLocalIP (/data/data/org.nativescript.barcodescanner/files/app/services/app-settings.service.js:19:25)
JS:     at AppComponent.ngOnInit (/data/data/org.nativescript.barcodescanner/files/app/app.component.js:13:42)
JS:     at Wrapper_AppComponent.detectChangesInInputProps (/AppModule/AppComponent/wrapper.ngfactory.js:18:53)
JS:     at DebugAppView._View_AppComponent_Host0.detectChangesInternal (/AppModule/AppComponent/host.ngfactory.js:30:26)
JS:     at DebugAppView.AppView.detectChanges (/data/data/org.nativescript.barcodescanner/files/app/tns_modules/@angular/core/bundles/core.umd.js:9305:18)
JS:     at DebugAppView.detectChanges (/data/data/org.nativescript.barcodescanner/files/app/tns_modules/@angular/core/bundles/core.umd.js:9410:48)
JS:     at ViewRef_.detectChanges (/data/data/org.nativescript.barcodescanner/files/app/tns_modules/@angular/core/bundles/core.umd.js:7398:24)
JS:     at /data/data/org.nativescript.barcodescanner/files/app/tns_modules/@angular/core/bundles/core.umd.js:6819:88
JS:     at Array.forEach (native)
JS: ERROR CONTEXT:
JS: [object Object]
JS: ns-renderer: ERROR BOOTSTRAPPING ANGULAR
JS: ns-renderer: Error in ./AppComponent class AppComponent_Host - inline template:0:0 caused by: Unexpected token u in JSON at position 0
JS:
JS: SyntaxError: Unexpected token u in JSON at position 0
JS:     at Object.parse (native)
JS:     at AppSettingsService.findLocalIP (/data/data/org.nativescript.barcodescanner/files/app/services/app-settings.service.js:19:25)
JS:     at AppComponent.ngOnInit (/data/data/org.nativescript.barcodescanner/files/app/app.component.js:13:42)
JS:     at Wrapper_AppComponent.detectChangesInInputProps (/AppModule/AppComponent/wrapper.ngfactory.js:18:53)
JS:     at DebugAppView._View_AppComponent_Host0.detectChangesInternal (/AppModule/AppComponent/host.ngfactory.js:30:26)
JS:     at DebugAppView.AppView.detectChanges (/data/data/org.nativescript.barcodescanner/files/app/tns_modules/@angular/core/bundles/core.umd.js:9305:18)
JS:     at DebugAppView.detectChanges (/data/data/org.nativescript.barcodescanner/files/app/tns_modules/@angular/core/bundles/core.umd.js:9410:48)
JS:     at ViewRef_.detectChanges (/data/data/org.nativescript.barcodescanner/files/app/tns_modules/@angular/core/bundles/core.umd.js:7398:24)
JS:     at /data/data/org.nativescript.barcodescanner/files/app/tns_modules/@angular/core/bundles/core.umd.js:6819:88
JS:     at Array.forEach (native)
8:46:00 AM - Compilation complete. Watching for file changes.

my app.component.ts:

import { Component, OnInit } from "@angular/core";
import { RouterExtensions } from 'nativescript-angular/router';
import { RestService } from './services/rest.service';
import { AppSettingsService } from './services/app-settings.service';


@Component({
    selector: "main",
    template : "<page-router-outlet></page-router-outlet>"
})
export class AppComponent implements OnInit {

    constructor(private restService: RestService, private appSettingsService: AppSettingsService, private routerExtensions: RouterExtensions) {

    }

    ngOnInit() {
        let ip = this.appSettingsService.findLocalIP();
           if (ip !== null) {
               this.restService.init(ip);
           } else if (ip === null) {
               this.routerExtensions.navigate(['settings']);
        }
}

my app-settings.service:

import { Injectable } from '@angular/core';
import * as appSettings from 'application-settings';

@Injectable()
export class AppSettingsService {

saveLocalIP(ip: string): void {
  let localData = appSettings.getString('retail_mobile');
  if (localData) {
    localData = JSON.parse(localData);
  } else {
    localData = "";
 }
let saveData = {localIP:ip};
appSettings.setString('retail_mobile', JSON.stringify(saveData));   
}

findLocalIP() {
   let data = JSON.parse(appSettings.getString('retail_mobile'));
   if (data === null) {     
    console.log("No entry found in local storage...");
    return null;
   }

if(data && !data.localIP) {
    console.log("no local ip found in localStorage...")
    return null;
}

return data.localIP;
}

constructor() { }
}

Solution

  • Your ngOnInit is calling the method findLocalIP() in the service, and that's where the error happens.

    Your problem should be in the following line:

    let data = JSON.parse(appSettings.getString('retail_mobile'));
    

    It's trying to parse something that is not parsable.

    The problem here seems to be the mismatch. appSettings.getString is returning a string, therefore it cannot be parsed. By removing JSON.parse that should clear things out.

    let data = appSettings.getString('retail_mobile')
    

    If you want/need to use use JSON, which I would expect, you have to actually convert it to json and back somehow, e.g like below. It's not pretty, but should work.

    findLocalIP() {
       let d = appSettings.getString('retail_mobile'); // add
       let d1 = JSON.stringify(d); // make it json
       let data = JSON.parse(d1); // now parse it
       if (data === null) {     
        console.log("No entry found in local storage...");
        return null;
       }
    

    Just to set an example with string/json:

    retail_mobile = "{ something: "something" }" This might look like JSON, but it is not, it's a string.

    If you try console.log(JSON.parse(retail_mobile)) it will throw you that error that you have.

    BEFORE parsing you actually have to JSON.stringify it, so the following commands in this order would not produce an error:

    retail_mobile = "{ something: "something" }"
    let data = JSON.stringify(retail_mobile); 
    console.log(JSON.parse(data));
    

    And as a comment to you for referring that the errors point to .js-files. At runtime TS is compiled as JS, so it doesn't know or care about TS-files, therefore errors point to JS-files.