1

ERROR:

core.es5.js?0445:1084 ERROR SyntaxError: Unexpected token < in JSON at position 0
    at JSON.parse (<anonymous>

SITUATION:

What I am trying to achieve is to pre-select the choice the user already made previously and prevent him from voting twice.


CODE:

component.html

<article class="panel panel-default">
    <div class="panel-body">
      {{ poll.title }}
      <br>
      <br>
      <form #form="ngForm">
        <fieldset [disabled]="alreadyVotedFor(-1)">
          {{ poll.counter1 }} votes <input type="radio" id="{{ poll.choice1 }}" name="my_radio" value="{{ poll.choice1 }}" (click)="onChoice1(form)" [checked]="alreadyVotedFor(1)">  {{ poll.choice1 }}
          <br>
          {{ poll.counter2 }} votes <input type="radio" id="{{ poll.choice2  }}" name="my_radio" value="{{ poll.choice2 }}" (click)="onChoice2(form)" [checked]="alreadyVotedFor(2)">  {{ poll.choice2 }}
        </fieldset>
      </form>

    </div>
    <footer class="panel-footer">
        <div class="author">
            {{ poll.username }}
        </div>
        <div class="config" *ngIf="belongsToUser()">
            <a (click)="onEdit()">Edit</a>
            <a (click)="onDelete()">Delete</a>
        </div>
    </footer>
</article>

component.ts

votes: any;

    ngOnInit() {
        this.pollService.voted(this.poll, localStorage.getItem('userId')).subscribe(
            data => {
                this.votes = data.votes;
                console.log("NGONINIT this.votes: "+ this.votes);
            },
            err => { console.log("NGONINIT ERROR: "+ err) },
            () => { console.log("SUBSCRIBE COMPLETE this.votes: "+ this.votes); }
        );
    }

    alreadyVotedFor(choice: number) {
      let result = "";
      if (this.votes) {
          console.log("THIS.VOTES: "+this.votes);
          for (var i = 0; i < this.votes.length; i ++) {
              if (this.votes[i].poll == this.poll.pollId) {
                  result = "disabled";
                  if (this.votes[i].choice == choice) {
                      result =  "selected";
                  }
              }
          }
      }
      return result;
  }

service

voted(poll: Poll, userID: string) {
    return this.http.get('http://localhost:3000/'+userID)
                    .map(response => response.json());
}

routes/user.js

router.get('/:userid', function (req, res, next) {
  var userId = req.params.userid;
  User.findById(userID, function (err, user) {
    console.log("USER JSON? :"+user.json());
    return res.send(user.json());
  });
});

models/user

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var mongooseUniqueValidator = require('mongoose-unique-validator');

var schema = new Schema({
    firstName: {type: String, required: true},
    lastName: {type: String, required: true},
    password: {type: String, required: true},
    email: {type: String, required: true, unique: true},
    polls: [{type: Schema.Types.ObjectId, ref: 'Poll'}],
    votes: [{
      poll: {type: Schema.Types.ObjectId, ref: 'Poll'},
      choice: {type: Number},
    }],
});

schema.plugin(mongooseUniqueValidator);

module.exports = mongoose.model('User', schema);
Coder1000
  • 4,071
  • 9
  • 35
  • 84
  • usually this error is result of wrong formatted json that javascript trying to load through ajax request. for example: {'name':'shlomo'} instead of {"name":"shlomo"} – happyZZR1400 May 21 '17 at 10:31
  • @happyZZR1400 Thanks for the insight ! But I really don't understand where or how my json could be incorrectly formatted :/ – Coder1000 May 21 '17 at 10:32
  • I don't have to look any further than `"Unexpected token <"` to know that the response is getting HTML and not JSON. Note that `<` is the opening of a tag. Easily debugged by simply doing `.do( response => console.log(response.text())` – Neil Lunn May 21 '17 at 10:32
  • @NeilLunn I agree, I just don't see how or why that happens :/ I googled for a lot of time but could not find what was wrong in my code. There are already plenty of similar questions on SO but each have a different solution. – Coder1000 May 21 '17 at 10:33
  • @Coder1000 you can check the `Network tab` of browser to see the response & verify which api is getting HTML response – Agam Banga May 21 '17 at 10:35
  • Are you possibly running your angular app on port 3000? At any rate whatever server there is returning HTML and not JSON. – Neil Lunn May 21 '17 at 10:35
  • Yes, but if you look at my route, I am returning json am I not ? :( – Coder1000 May 21 '17 at 10:36
  • Moreover a hardcoded `'http://localhost:3000` isn't going to help anyone else trying to run your app. – Neil Lunn May 21 '17 at 10:36
  • And there is no such thing as `user.json()` it's `res.json(user)`. So my guess is the server is returning 500 status and an error message in HTML. – Neil Lunn May 21 '17 at 10:38
  • @AgamBanga Checked the network tab. It's indeed text/html and it's indeed my /:userid route. But I don't understand why. – Coder1000 May 21 '17 at 10:39
  • @NeilLunn Thx for the correction. Sadly, the network tab tells me it is still returning html. I am confused as to why. – Coder1000 May 21 '17 at 10:41
  • Possible duplicate of ["SyntaxError: Unexpected token < in JSON at position 0" in React App](http://stackoverflow.com/questions/37280274/syntaxerror-unexpected-token-in-json-at-position-0-in-react-app) – Estus Flask May 21 '17 at 10:45
  • The question lacks http://stackoverflow.com/help/mcve . If the problem is server side then there should be full code for Node app that is relevant for this path. It's not obvious that routes/user.js route will respond to `http://localhost:3000/'+userID` request. And Angular app is irrelevant here. The problem should be visible with plain request from address bar. – Estus Flask May 21 '17 at 10:49
  • @estsus do you want me to send you the zip with the code ? – Coder1000 May 21 '17 at 10:50
  • It's not for me. The question should contain http://stackoverflow.com/help/mcve . Otherwise it is considered offtopic. – Estus Flask May 21 '17 at 10:51
  • @etsus All right. I am just having a very hard imagining how I could make an mcve for this since the app is rather large and divived in many many files. It's impossible to make an mcve. All I could do is send the zip :/ – Coder1000 May 21 '17 at 10:52
  • Then make it small, containing only relevant route yet still be able to replicate the error. This is the work that the asker has to do in order to not waste answerers' time and be able to receive the answer. And there's a good chance that you will figure out what's wrong when doing that. Considering that this isn't your first day on SO, you should already know how this works. – Estus Flask May 21 '17 at 10:59
  • @etsus Well, you are correct. I did that many times before. But since I am new to angular, I frankly don't see how to do it here :/ I put the app online live on heroku and am ready to provide the full code in a zip. I don't know what else I could do :/ – Coder1000 May 21 '17 at 11:03
  • This has nothing to do with Angular. This is purely Node problem. Provide code where you use routes/user.js and the file that uses it, etc, until becomes obvious that it is mounted to / and should respond to http://localhost:3000/userID request. Until then you're on your own with your issue. – Estus Flask May 21 '17 at 11:09
  • @estus That's the code I already put in my question, no ? I am confused :/ There is no other code interacting with the route to my knowledge. – Coder1000 May 21 '17 at 11:13
  • routes/user.js is used somewhere like app.js, and it's not clear where. Sorry, can't help, it's highly unlikely that somebody else can. – Estus Flask May 21 '17 at 11:14
  • @estus You're right. There isn't enough info. Here is the zip: https://www.dropbox.com/s/o64y39sni3gross/Voting%20App.zip?dl=0 – Coder1000 May 21 '17 at 11:21

1 Answers1

5

This error happens when server responds with HTML instead of JSON, particularly when a route is not found and the response is 404 page.

It's unlikely that API has the only route which is mounted at root and available as http://localhost:3000/'+userID, just because it's not possible for the server to do anything else in this case.

If the route is mounted to some path, like

app.use('/user', userRoutes);

then the requests should be performed to this path as well

return this.http.get('http://localhost:3000/user/'+userID)
Estus Flask
  • 206,104
  • 70
  • 425
  • 565