1

I am creating a single-page AngularJS web app. My app needs to be able to query a backend service to get some information about a user's state, and this state information needs to be available to the various pieces of the single-page app. I created a service to manage this functionality, but I'm having trouble hooking things up in a way that seems reasonable to me.

Initially, I had things set up like this...

<service.js>
...
var url = 'www.my-backend.com';
this.val = [
    {
        name: 'undefined',
        isValid: false
    }
];
$http.get(url, {})
    .success (function (data) {
        this.val = data;
    })
    .error (function () {
        this.val =  [
            {
                name: 'error',
                isValid: false
            }
         ];
    });
...

And then in my controller...

<controller.js>
...
$scope.val = service.val
...

This didn't work though (val.name was 'undefined'), presumably because service.val was bound to the controller's $scope before the get request had a chance to terminate. However, that does seem at odds with what I read here.

The next thing I did was this...

<service.js>
...
var url = 'www.my-backend.com';
this.valPromise = $http.get(url, {});
...

And then in my controller...

<controller.js>
...
$scope.val = [
    {
        name: 'undefined',
        isValid: false
    }
];
service.valPromise
    .success (function (data) {
        $scope.val = data;
    })
    .error (function () {
        $scope.val =  [
            {
                name: 'error',
                isValid: false
            }
         ];
    });
...

This worked, but I didn't like it. I feel like that logic belongs in the service.

So the next thing I did was work through the various suggestions that I found here, although none of them seemed to have the desired effect. I also saw this, but it seems like overkill and not really applicable to my problem.

Ideally I'd really like to figure out how to get my first attempt working (tightly bind my service variable to my controller scope by reference), but if that's not something that can really be done within the Angular framework, I'm happy to use some kind of watch behavior. Can anyone spot what I'm doing wrong or why my service variable isn't getting properly hooked up to my controller?

Community
  • 1
  • 1
Dan Forbes
  • 2,354
  • 2
  • 26
  • 55

2 Answers2

2

In your $http callbacks this is not the service. You'll find plenty of answers about the meaning of this on SO. You need to refer to the service via a variable.

The second problem is that this.val = data; would assign a new value to the service, but doesn't change the data in the scope, which still points to the old array. So you need to copy the new data to the existing array.

var service = this;
$http.get(url, {})
.success (function (data) {
    angular.copy(data, service.val);
})
a better oliver
  • 24,069
  • 2
  • 48
  • 59
  • I up-voted your answer because it seemed to point out an error that I was making, but it doesn't look like it solves the problem - although you may concede that point in the final part of your answer. Per your suggestion, in my service, I bind `this` to a variable `service`, and then in my callbacks I set the value of `service.val`. I want to use the information returned by the service to populate data on the page controlled by my controller, but when that page loads `name.val` is still 'undefined' and so there is no useful information displayed on my page. Am I missing something? – Dan Forbes Sep 17 '14 at 16:48
  • @DanForbes If you use it on your page like `{{val.name}}`, then it really doesn't matter when `name` is updated. How do you use it? – a better oliver Sep 17 '14 at 16:53
  • I don't use it like `{{val.name}}`. I use it in populating a select box: ` – Dan Forbes Sep 17 '14 at 16:57
  • @DanForbes That has the same implications. But I missed one obvious point and updated the question. – a better oliver Sep 17 '14 at 17:50
  • This works perfectly and is exactly what I needed. Thanks, @zeroflagL! – Dan Forbes Sep 19 '14 at 20:16
0

I ran into this problem the other day. The reason it does not get set is because there is a race condition and because the data access is inside the service layer, it will lose every time. It seems like there should be a easy way to do this. I ended up just having my initial controller make the data access calls and set the properties in the service for other controllers to get.

rleffler
  • 331
  • 4
  • 13