1
votes

Relatively new to node.js, trying to get a JS object from Angular2 to my node.js route but i'm always getting a standard "unexpected token blah blah at index 0" from the native object parser.

The object gets up to my node factory just fine but fails when posting to the route.

This is the JSON that is being sent to the route:

{"SQLServerHostName":"MININT-MT0DKDT","SQLServerDBName":"ContosoRetailDW","SQLServerUserName":"svc_sql_D3","SQLServerPassword":"Inspur123#@!","StoredProcedureName":"[dbo].[d3Test]"}

This is the error i'm receiving in the dev console.

angular2.dev.js:23083 EXCEPTION: SyntaxError: Unexpected token S in JSON at position 0BrowserDomAdapter.logError @ angular2.dev.js:23083BrowserDomAdapter.logGroup @ angular2.dev.js:23094ExceptionHandler.call @ angular2.dev.js:1185(anonymous function) @ angular2.dev.js:12591NgZone._notifyOnError @ angular2.dev.js:13635onError @ angular2.dev.js:13539Zone.run @ angular2-polyfills.js:1247(anonymous function) @ angular2.dev.js:13558zoneBoundFn @ angular2-polyfills.js:1220 angular2.dev.js:23083 STACKTRACE:BrowserDomAdapter.logError @ angular2.dev.js:23083ExceptionHandler.call @ angular2.dev.js:1187(anonymous function) @ angular2.dev.js:12591NgZone._notifyOnError @ angular2.dev.js:13635onError @ angular2.dev.js:13539Zone.run @ angular2-polyfills.js:1247(anonymous function) @ angular2.dev.js:13558zoneBoundFn @ angular2-polyfills.js:1220 angular2.dev.js:23083 SyntaxError: Unexpected token S in JSON at position 0 at Object.parse (native) at XMLHttpRequest.req.onload [as _onload] (http://localhost:1557/app/services/xhr-factory.service.js:17:33) at Zone.run (http://localhost:1557/node_modules/angular2/bundles/angular2-polyfills.js:1243:24) at Zone.run (http://localhost:1557/node_modules/angular2/bundles/angular2.dev.js:13558:32) at XMLHttpRequest.zoneBoundFn (http://localhost:1557/node_modules/angular2/bundles/angular2-polyfills.js:1220:26)

-----async gap----- Error at _getStacktraceWithUncaughtError (http://localhost:1557/node_modules/angular2/bundles/angular2-polyfills.js:2244:29) at Zone.fork (http://localhost:1557/node_modules/angular2/bundles/angular2-polyfills.js:2293:47) at Zone.bind (http://localhost:1557/node_modules/angular2/bundles/angular2-polyfills.js:1218:53) at XMLHttpRequest.obj.addEventListener (http://localhost:1557/node_modules/angular2/bundles/angular2-polyfills.js:1503:95) at XMLHttpRequest.desc.set [as onload] (http://localhost:1557/node_modules/angular2/bundles/angular2-polyfills.js:1449:19) at eval (http://localhost:1557/app/services/xhr-factory.service.js:11:24) at lib$es6$promise$$internal$$initializePromise (http://localhost:1557/node_modules/angular2/bundles/angular2-polyfills.js:515:10) at new lib$es6$promise$promise$$Promise (http://localhost:1557/node_modules/angular2/bundles/angular2-polyfills.js:806:10) at _sendRequest (http://localhost:1557/app/services/xhr-factory.service.js:7:16) at Object.post (http://localhost:1557/app/services/xhr-factory.service.js:39:28)

-----async gap----- Error at _getStacktraceWithUncaughtError (http://localhost:1557/node_modules/angular2/bundles/angular2-polyfills.js:2244:29) at Zone.fork (http://localhost:1557/node_modules/angular2/bundles/angular2-polyfills.js:2293:47) at arguments.(anonymous function) (http://localhost:1557/node_modules/angular2/bundles/angular2-polyfills.js:1671:82)

-----async gap----- Error at _getStacktraceWithUncaughtError (http://localhost:1557/node_modules/angular2/bundles/angular2-polyfills.js:2244:29) at Zone.fork (http://localhost:1557/node_modules/angular2/bundles/angular2-polyfills.js:2293:47) at NgZone._createInnerZone (http://localhost:1557/node_modules/angular2/bundles/angular2.dev.js:13546:39) at new NgZone (http://localhost:1557/node_modules/angular2/bundles/angular2.dev.js:13412:32) at createNgZone (http://localhost:1557/node_modules/angular2/bundles/angular2.dev.js:12475:12) at PlatformRef_.application (http://localhost:1557/node_modules/angular2/bundles/angular2.dev.js:12550:31) at Object.bootstrap (http://localhost:1557/node_modules/angular2/bundles/angular2.dev.js:24805:64) at execute (http://localhost:1557/app/boot.js:14:23) at ensureEvaluated (http://localhost:1557/node_modules/systemjs/dist/system.src.js:3186:26) at Object.execute (http://localhost:1557/node_modules/systemjs/dist/system.src.js:3304:13)BrowserDomAdapter.logError @ angular2.dev.js:23083ExceptionHandler.call @ angular2.dev.js:1188(anonymous function) @ angular2.dev.js:12591NgZone._notifyOnError @ angular2.dev.js:13635onError @ angular2.dev.js:13539Zone.run @ angular2-polyfills.js:1247(anonymous function) @ angular2.dev.js:13558zoneBoundFn @ angular2-polyfills.js:1220 angular2.dev.js:1206 Uncaught SyntaxError: Unexpected token S in JSON at position 0req.onload @ xhr-factory.service.ts:28Zone.run @ angular2-polyfills.js:1243(anonymous function) @ angular2.dev.js:13558zoneBoundFn @ angular2-polyfills.js:1220

Here is the Angular2 component that calls the factory

import {Component} from 'angular2/core';
import {WizardStepOneComponent} from './wizardStepOne.component'
import {WizardStepTwoComponent} from './wizardStepTwo.component'
import {WizardStepThreeComponent} from './wizardStepThree.component'
import {ConfigurationData} from '../classes/configurationData'
import {Report} from '../classes/report'
import {ChartType} from '../classes/chartType'
import {WizardFactory} from '../services/WizardFactory.service'

@Component({
    selector: 'wizardMain',
    templateUrl: '../../partials/_wizardMain.html',
    directives: [WizardStepOneComponent
               , WizardStepTwoComponent
               , WizardStepThreeComponent],
    providers: [Report, ChartType]
})

export class WizardMainComponent{
        configurationData: ConfigurationData;
        report: Report;
        chartType: ChartType;
        step1Show:boolean;
        step2Show:boolean;
        step3Show:boolean;
        step4Show:boolean;

        configMainShow:boolean;
        configSQLServerShow:boolean;
        configMySQLShow:boolean;
        configHadoopShow:boolean;
        configNoSQLShow:boolean;

    constructor(public _report: Report
               ,public _chartType: ChartType){
        this.report = _report;
        this.chartType = _chartType;
        this.hideAll();
        this.loadStep(1);
    }

    hideAll(){
        this.step1Show = false;
        this.step2Show = false;
        this.step3Show = false;
        this.step4Show = false;

        this.configMainShow = false;
        this.configSQLServerShow = false;
        this.configMySQLShow = false;
        this.configHadoopShow = false;
        this.configNoSQLShow = false;
    }

    loadAdminPanel(){

    }

    loadMainPanel(){

    }

    loadStep(stepNumber){
        switch(stepNumber)
        {
            case 1:
            {
                this.step1Show = true;
                this.step2Show = false;
                this.step3Show = false;
                this.step4Show = false;

                this.configMainShow = false;
                this.configSQLServerShow = false;
                this.configMySQLShow = false;
                this.configHadoopShow = false;
                this.configNoSQLShow = false;
                break;
            }
            case 2:
            {   
                this.step1Show = false;
                this.step2Show = true;
                this.step3Show = false;
                this.step4Show = false;

                this.configMainShow = false;
                this.configSQLServerShow = false;
                this.configMySQLShow = false;
                this.configHadoopShow = false;
                this.configNoSQLShow = false;

                break;
            }
            case 3:
            {
                this.step1Show = false;
                this.step2Show = false;
                this.step3Show = true;
                this.step4Show = false;

                this.configMainShow = false;
                this.configSQLServerShow = false;
                this.configMySQLShow = false;
                this.configHadoopShow = false;
                this.configNoSQLShow = false;
                break;
            }
            case 4:
            {
                this.step1Show = false;
                this.step2Show = false;
                this.step3Show = false;
                this.step4Show = true;

                this.configMainShow = false;
                this.configSQLServerShow = false;
                this.configMySQLShow = false;
                this.configHadoopShow = false;
                this.configNoSQLShow = false;
                break;
            }
        }
    }

    setConfigurationData(ConfigData: ConfigurationData){
        this.configurationData = ConfigData;
    }

    setReportName(ReportName: string){
        this.report.ReportName = ReportName;
        this.loadStep(2);
    }

    setChartType(ChartTypeID: number){
        this.chartType.ChartTypeID = ChartTypeID;
        WizardFactory.getColumnProperties(this.configurationData).then((data) => {
            console.log("SQL Server Response: " + data);
        });
        this.loadStep(3);
    }

    setXAxis(XAxis: string){
        this.configurationData.XAxis = XAxis;        
    }

    setYAxis(YAxis: string){
        this.configurationData.YAxis = YAxis;
        this.loadStep(4);
    }
}

It gets to the factory just fine here:

import {$http} from './xhr-factory.service';
import {ConfigurationData} from '../classes/configurationData';

export const WizardFactory = {
    getColumnProperties: function (currentConfig) {
        console.log("Current Config in Factory: " + JSON.stringify(currentConfig));
        return $http.post('/api/getColumnProperties', currentConfig);
    }
}

And to my XHR Handler:

    export const $http = {
    get: function(url: string) {
        return _sendRequest(url, null, 'GET');
    },
    post: function(url: string, payload: any){
        return _sendRequest(url, payload, 'POST');
    },
    put: function(url: string, payload: any){
        return _sendRequest(url, payload, 'PUT');
    },
    delete: function(url: string, payload: any){
        return _sendRequest(url, null, 'DELETE');
    }
}


function _sendRequest(url: string, payLoad: any, type: string): Promise<JSON> {
        return new Promise(function(resolve, reject) {
            var req = new XMLHttpRequest();
            req.open(type, url);
            req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");

            req.onload = function() {
                if (req.status == 200) {
                    console.log("Resolved");
                    resolve(JSON.parse(req.response));
                } else {
                    reject(JSON.parse(req.response));
                }
            };

            req.onerror = function() {
                reject(JSON.parse(req.response));
            };

            if (payLoad) {
                req.send(JSON.stringify(payLoad));
            } else {
                req.send(null);
            }
        });
    }

But it will not get to the route I have defined; which i've manipulated about 100 times now to try and get the syntax right:

var express = require('express');
var wizardRouter = express.Router();
var sql = require('mssql');

var sqlReturnDefinitionQuery = "SET NO_BROWSETABLE ON; \
                                SET FMTONLY ON; \
                                EXEC {0}; \
                                SET FMTONLY OFF; \
                                SET NO_BROWSETABLE OFF";
/*Get Stored Procedure Schema*/
wizardRouter.post('/getColumnProperties', function (req, res, next) {
    console.log("In router");
    _currentConfig =  JSON.parse(req.params.currentConfig);

    console.log("Current Config in Router: " + req.params.currentConfig);

    var config = {
        user: _currentConfig.SQLServerUserName,
        password: _currentConfig.SQLServerPassword,
        server: _currentConfig.SQLServerHostName,
        database: _currentConfig.SQLServerDBName
    };

    var finalReturnDefinitionQuery = sqlReturnDefinitionQuery.replace("{0}", _currentConfig.StoredProcedureName);

    sql.connect(config, function () {
        if(err) console.log(err);

        var request = new sql.Request();

        request.query(finalReturnDefinitionQuery, function(err, recordset){
            if(err) console.log(err);

            res.send(recordset);
        });
    });
});
module.exports = wizardRouter;

And finally here is my node server file:

var express = require('express');
var path = require('path');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var index = require('./routes/index');
var wizard = require('./routes/wizard');

var app = express();

// view engine setup
app.set('/', path.join(__dirname, 'partials'));
app.set('view engine', 'ejs');
app.engine('html', require('ejs').renderFile);

app.use('/js', express.static(__dirname + '/js'));
app.use('/app', express.static(__dirname + '/app'));
app.use('/content', express.static(__dirname + '/content'));
app.use('/node_modules', express.static(path.join(__dirname, '/node_modules')));
app.use('/partials', express.static(path.join(__dirname, '/partials')));


app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
    extended: false
}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', index);
app.use('/api/', wizard);

// catch 404 and forward to error handler
app.use(function (req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

var server = app.listen(1557, function () {
    var host = 'localhost';
    var port = server.address().port;
    console.log('App listening at http://%s:%s', host, port);
});

module.exports = app;

Any help would be greatly appreciated; this is driving me nuts.

1
The error is being thrown by Angular, so apparently it's not receiving the data that it expects. Take a look in your browser's dev tools to see what the actual response from the Express server is.robertklep

1 Answers

1
votes

So, I believe it's failing on your req.onload function because the returned data from your server is invalid JSON. It's the JSON.parse(req.response) that is throwing the error.

I noticed in your server code for that route, you aren't sending stringified data back to your Angular app. Try setting res.send(recordset); to res.send(JSON.stringify(recordset));