0

It's the first time I'm using Angular's watch function and apparently I don't get it to work. I have a service called apiService, which has a variable myFile. I am injecting the service into my controller and want to watch the apiService.myFile value for a change. Unfortunately the watch only gets called on opening the webpage, not when the apiService.myFile variable actually changes. Here is the code for the watch:

$scope.$watch(function(){return apiService.myFile}, function (newVal, oldVal, scope) {
    console.log("service changed: "+newVal +" : "+oldVal+" : "+ scope);
});

Why isn't it being called when myFilechanges?

UPDATE 1: this is how I update the value of apiService.myFile inside the service

ApiService.prototype.uploadFile = function(fileContent) {
    $.ajax({
        url: "/space_uploadFile/",
        type: "POST",
        dataType: "json",
        data: {
            fileContent: fileContent
        },

        contentType: "application/json",
        cache: false,
        timeout: 5000,
        complete: function() {
          //called when complete
          console.log('process complete');
        },
        success: function(data) {
            this.myFile =data;
            console.log("this.myFile: "+this.myFile);
            console.log('process success');
       },
        error: function() {
          console.log('process error');
        },
      });

};
suMi
  • 1,506
  • 1
  • 15
  • 29

2 Answers2

2

I added this inside a plunkr (as you didn't) and this works for me:

Sidenote: next time create an example demonstrating your problem (plunkr) so we can eliminate the case of your problem (e.g. typo).

var app = angular.module('app', []);

app.controller('mainController', function($scope, apiService) {

  $scope.changeValue = function() {
    apiService.myFile += "!";
  };

  $scope.$watch(function(){return apiService.myFile}, function (newVal, oldVal, scope) {
    console.log("service changed: "+newVal +" : "+oldVal+" : "+ scope);
    $scope.someValue = newVal;
  });
});

app.service('apiService', function() {
  this.myFile = "Test";
});

And the corresponding HTML:

<body ng-controller="mainController">
  <h1>Hello Plunker!</h1>
  {{someValue}}
  <button ng-click="changeValue()">Click</button>
</body>

https://plnkr.co/edit/DpDCulalK1pZ8J0ykh2Z?p=preview

BTW: The $watch part is a copy from your question and it simply works for me.

Edit: Apparantly the OP was using $.ajax to do ajax calls and the value was updated inside the succeshandler (outside the Angular context). So there was no digest cycle triggered here. To fix this you should use the $http service provided by angular (or work your way around it without).

var self = this;
self.$http.post("/space_uploadFile/",
{ fileContent: fileContent },
{ 
    cache: false,
    timeout: 5000
})
.then(function (data) {
    self.myFile = data;
    console.log("self.myFile: " + self.myFile);
    console.log('process success');
},
function () {
    console.log('process error');
});

Edit2: Apparantly the OP was also using this in the succeshandler to acces variable on the controller. This won't work, so I used the self pattern in the sample above to solve it.

Frederik Prijck
  • 1,324
  • 8
  • 15
  • if it simply works for you something is wrong in my controller then. Can it be because I do my ajax call inside the prototype of the service? `ApiService.prototype.uploadFile = function(fileContent) { $.ajax({...]);};` – suMi Sep 20 '16 at 06:33
  • Use $http instead of $.ajax. Because you are leaving the Angular Context by using $.ajax hence changes happening inside the succeshandler won't trigger the angular's digest cycle. – Frederik Prijck Sep 20 '16 at 06:35
  • I added the code of how I am actually changing the variable inside the service – suMi Sep 20 '16 at 06:36
  • Updated my answer. – Frederik Prijck Sep 20 '16 at 06:43
  • I have to use this.$http.post otherwise $http is not found. and then it's still only triggering the watch on pageload but not when the variable changes – suMi Sep 20 '16 at 06:49
  • Yes that's obvious but I'll update my answer for you. – Frederik Prijck Sep 20 '16 at 06:52
  • So, is it working for you or are you still having problems ? – Frederik Prijck Sep 20 '16 at 06:52
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/123758/discussion-between-sumi-and-frederik-prijck). – suMi Sep 20 '16 at 06:53
-3

I am used to this syntax:

scope.$watch('name', function(newValue, oldValue) {
  scope.counter = scope.counter + 1;
});

where name is the name of your property - in this case myFile

Nils
  • 849
  • 9
  • 18
  • This only works for properties on the scope. The OP doesn't want this. He want's to watch a property of a service. – Frederik Prijck Sep 20 '16 at 06:15
  • then it might be a duplicate: http://stackoverflow.com/questions/12576798/angularjs-how-to-watch-service-variables – Nils Sep 20 '16 at 06:16
  • so the answer is not to use angular watch but something else? – suMi Sep 20 '16 at 06:19
  • Actually you can use a $watch. – Frederik Prijck Sep 20 '16 at 06:22
  • the angular watch is designed for watching changes in properties during the digest. It was simply not designed for services. My advice would be to implement a observer pattern in your service by yourself. that's what the linked answer suggests as well. – Nils Sep 20 '16 at 06:22
  • It actually is. Have a look at my plunkr . – Frederik Prijck Sep 20 '16 at 06:24
  • Well, I stand corrected - thanks for clarification :) – Nils Sep 20 '16 at 06:25
  • Basicly there's 2 ways to $watch: using a string ( the property on the $scope) or a function returning anything, this function will be called on every digest cycle. The return value will be used to decide the value has changed or not by keeping track of the previously item returned from this list vs the currently returning value. – Frederik Prijck Sep 20 '16 at 06:29