-1

I am trying to get a user by ID by creating an endpoint on the backend and querying it with the Angular Http service.

What is the correct syntax ?

Here is my current code:

service

voteOn(poll: Poll, userID: string, choice: number) {
  var user;
  this.http.get('/'+userID)
  .map(response => response.json())
  .subscribe(json => user = json )
        user.votes.push({poll, choice });
        const body = JSON.stringify(user);
        const headers = new Headers({'Content-Type': 'application/json'});
        const token = localStorage.getItem('token')
            ? '?token=' + localStorage.getItem('token')
            : '';
        return this.http.patch('https://voting-app-10.herokuapp.com/user'+token, body, {headers: headers})
            .map((response: Response) => response.json())
            .catch((error: Response) => {
                this.errorService.handleError(error);
                return Observable.throw(error);
            })
            .subscribe();
}

route

router.get('/:userid', function (req, res, next) {
  var userId = req.params.userid;
  UserModel.findById(userID, function (err, user) {
    return res.send(user);
  });
});

Obviously this is incorrect. The user variable is not defined when user.votes.push is called. How can I assign the result of my first query to user correctly ?


SOLUTION:

voted(poll: Poll, userID: string, choice: number) {
      var user;
      this.http.get('/'+userID)
      .map(response => response.json())
      .subscribe(
            json => {
              user = json;
              var result = "";
              for (var i = 0; i < user.votes.length; i ++) {
                if (user.votes[i].poll == poll.pollId) {
                  result = "disabled";
                  if (user.votes[i].choice == choice) {
                    result =  "cheked";
                  }
                }
              }
              console.log("RESULT:"+result);
              return result;
          }
      )
    }
Coder1000
  • 4,071
  • 9
  • 35
  • 84
  • 1
    What do you mean *"the correct syntax"*? Are you getting syntax errors from the compiler? Give a [mcve]. If you just mean "how do I do this", then I'd recommend doing some research; start with the official docs. – jonrsharpe May 19 '17 at 16:49
  • @jonrsharpe I already read the docs. I know what methods are at my disposition, but being new to angular, I some trouble with implementation in this case. – Coder1000 May 20 '17 at 11:14
  • Then be specific about the *"trouble"* - errors? Unexpected behaviour? Help other people understand and recreate your problem. And please don't roll back valid edits. – jonrsharpe May 20 '17 at 11:15
  • @jonrsharpe You are right. Let me edit my question. – Coder1000 May 20 '17 at 11:16
  • Put a [mcve] *in the question*. As it stands, despite the indentation, you are trying to manipulate `user` *outside the subscription* where it will not yet be available. Observables are asynchronous, that's the whole point of them; see e.g. http://stackoverflow.com/q/37867020/3001761. – jonrsharpe May 20 '17 at 11:27
  • @jonrsharpe Actually, I understand how Observables work: If you read my question again, you will see I am aware that because of it's async nature, my user var will be undefined when used. Again, the only thing I was looking for was the syntax, and you just provided it to me with the example you pointed to. Could you please write an answer so I can accept it and reward you ? – Coder1000 May 20 '17 at 13:07
  • @jsonsharpe Actually, I could have been a bit more precise in my question and specifically pointing to my understanding that the error was caused because of async of Observable instead of assuming it was obvious to everyone. – Coder1000 May 20 '17 at 13:11
  • That would have been helpful; the question was unclear also because you ask after syntax but your *syntax* is not the problem. If the other question's answers have solved your problem I'd recommend deleting this one, as you don't have enough rep to mark it as duplicate yourself. – jonrsharpe May 20 '17 at 13:13
  • @jonrsharpe I would love to delete it but I can't do so because of the incorrect answer below which is not deleted. I cannot delete a question which has already accrued an answer. – Coder1000 May 20 '17 at 13:14
  • I thought you could delete them if there was only one answer and it wasn't upvoted: https://meta.stackexchange.com/q/5221/248731 – jonrsharpe May 20 '17 at 13:17
  • @jonrsharpe I can't. Here is the message I get if I try: "We do not recommend deleting questions with answers because doing so deprives future readers of this knowledge. Repeated deletion of answered questions can result in your account being blocked from asking. Are you sure you wish to delete?" – Coder1000 May 20 '17 at 13:18
  • @jonrsharpe I obviously don't want to be blocked from asking :D – Coder1000 May 20 '17 at 13:18
  • That doesn't say you can't, it says they don't recommend doing it a lot. You're not depriving other users of much getting rid of one answer that nobody has so far voted up as useful. But it's up to you. – jonrsharpe May 20 '17 at 13:20
  • @jonrsharpe I agree with you. But losing the right to ask questions is just as good as an absolute impossibility in this case for me. – Coder1000 May 20 '17 at 13:21

1 Answers1

-1

Speaking only of the Angular2 side here (not as familiar with Express, but the route handler looks right):

At a high level, this looks reasonable. Your core issue is that you are returning a Subscription inside a lambda passed to Observable.map(), which will wrap it in an Observable: Observable. In general, from client method you want to return an Observable<> rather than a Subscription<>, and let the person consuming the client decide how to subscribe to the result:

return this.http.patch(
                    'https://voting-app-10.herokuapp.com/user'+token, 
                    body, {headers: headers})
                .map((response: Response) => response.json())
                .catch((error: Response) => {
                    this.errorService.handleError(error);
                    return Observable.throw(error);
                })

This will return Observable, though you could get better typing if you define an interface and cast response.json() to it.

To avoid the outer observable wrapping, consider instead using switchMap:

this.http.get('/'+userID)
    .switchMap(user => 
        user.votes.push({poll, choice });
        const body = JSON.stringify(user);
        const headers = new Headers({'Content-Type': 'application/json'});
        const token = localStorage.getItem('token')
            ? '?token=' + localStorage.getItem('token')
            : '';
        return this.http.patch('https://voting-app-10.herokuapp.com/user'+token, body, {headers: headers})
            .map((response: Response) => response.json())
            .catch((error: Response) => {
                this.errorService.handleError(error);
                return Observable.throw(error);
            });
      )

For general usage of Angular Http object (plus a boilerplate REST client base class), take a look at: https://gist.github.com/lokitoth/d71794061e7e03bb8c1bf73648d6733d

J Alber
  • 39
  • 4