문제

I have a promise chain that looks like this ...

this.getFile(fileId).then(updateFile).then(displayAllDoneMessage);

where getFile() and updateFile() each use ngResource to construct the appropriate JSON call, and then return the $resource.$promise.

The chain fires OK, but I'm having a problem accessing $scope from within updateFile

So in getFile() I have

// this works
this.status.text = "fetching file"

But in updateFile() I have

// this fails at runtime because "this" is not $scope
this.status.text = "updating file"

What am I doing wrong, or what extra do I need to do to make $scope available within updateFile()?

I should possibly add that I'm using TypeScript in case that is significant.

도움이 되었습니까?

해결책 2

When you call this.getFile, the context is this, in your case, I guess this is the $scope object so this inside getFile is the $scope.

But updateFile and displayAllDoneMessage are invoked by the framework as a callback and this no longer refers to the $scope.

Try .bind to bind the $scope as the context:

this.getFile(fileId).then(updateFile.bind(this)).then(displayAllDoneMessage.bind(this));

For older browsers, you could include this script as a polyfill (quoted from the docs):

if (!Function.prototype.bind) {
  Function.prototype.bind = function (oThis) {
    if (typeof this !== "function") {
      // closest thing possible to the ECMAScript 5 internal IsCallable function
      throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
    }

    var aArgs = Array.prototype.slice.call(arguments, 1), 
        fToBind = this, 
        fNOP = function () {},
        fBound = function () {
          return fToBind.apply(this instanceof fNOP && oThis
                                 ? this
                                 : oThis,
                               aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    fNOP.prototype = this.prototype;
    fBound.prototype = new fNOP();

    return fBound;
  };
}

다른 팁

If you are using TypeScript and you want to maintain your this pointer, then you need to ensure you are using the lambda syntax.

Assuming you have saved off your $scope as a private/public variable in your constructor like this:

constructor(private $scope){ /* snip */ }

Then you can simply do this to ensure you are accessing your $scope like so:

this.getFile(fileid)
.then((result) => {
   return this.$scope.updateFile(result);
})
.then((result) => {
   return this.$scope.displayAllDoneMessage(result);
});

Under the hood this gets compiled down to something like the following:

//Save 'this' off to a closure
var _this = this;

_this.getFile(fileid)
.then(function(result){
   return _this.$scope.updateFile(result);
})
.then(function(result){
   return _this.$scope.displayAllDoneMessage(result);
});

TypeScipt uses a closure to maintain the appropriate references to this

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top