在$ scope。$ on事件中丢失此引用

时间:2015-06-25 15:25:28

标签: javascript angularjs typescript

我正在注册" $ routeChangeSuccessEvent"通过设置回调函数来自Angularjs。当事件被引发时,我无法通过"这个"来访问我的控制器实例。当前这个实例是未定义的。

我完整的TypeScript代码:

export class Ctlr {

    static $inject = ["$rootScope","$route"];

    constructor(private $scope: ng.IRootScopeService) {
        this.Scope = $scope;
        this.Title = "";
        //this.Scope.$on("$routeChangeSuccessEvent", this.onRouteChangeStart);
        this.RegisterEvents();
        }
    private RegisterEvents(): void {
        this.Scope.$on("$routeChangeSuccessEvent",(event: ng.IAngularEvent, args: any) => {
        //this is undefined
            console.log(this);
        });
    }
    public Scope: ng.IScope;
    public Title: string;

    public onRouteChangeStart(event: ng.IAngularEvent, args: any) {
        //this is undefined
        this.Title = args.$$route.name);
    }

}

}

我可以通过以下方式访问Title属性:

 private RegisterEvents(): void {
        var ref = this.Title;
        this.Scope.$on("$routeChangeSuccessEvent",(event: ng.IAngularEvent, args: any) => {
            ref = args.$$route.name;
        });
    }

但这不是一个真正的解决方案,因为angularJS不会更新其视图。似乎我没有抓住正确的参考。如果那不可能那么整个angularjs事件似乎都没有用 - 这是不可能的?

我也没有找到关于这种奇怪行为的话题。这个问题有解决方案吗?

4 个答案:

答案 0 :(得分:3)

触发回调时范围会发生变化,这就是this未定义的原因。

你做的另一个例子:

var ref = this.Title;

实际上只是创建一个Title的-copy-,因为它是一个原始类型(字符串)。这就是为什么它也没有用的原因。更新ref不会更新this.Title

通常的解决方法是将定义开始为:

var vm = this;

...
private RegisterEvents(): void {
    this.Scope.$on("$routeChangeSuccessEvent",(event: ng.IAngularEvent, args: any) => {
    //this is undefined
        console.log(vm);
    });
}

所以,不要在任何地方使用this,而是使用vm。请注意,vm可以根据需要命名。重要的一部分是在this范围内捕获对this的引用,其中this是您要在回调中使用的内容。这是有效的,因为bind 是一种基本类型,因为它是一个对象,而不是复制它,它需要一个引用。

您的另一个选择是使用可以应用于任何函数的this,此函数实质上告诉JavaScript $scope.$on("SomeEventHere", someCallbackFunction.bind(this)); 将等同于什么。 E.g。

var something = this;

这是您在此处使用的偏好问题,但通常我会看到人们使用import smart_open import io import csv testDict = [{ "fieldA": "8", "fieldB": None, "fieldC": "888888888888"}, { "fieldA": "9", "fieldB": None, "fieldC": "99999999999"}] fieldnames = ['fieldA', 'fieldB', 'fieldC'] f = io.StringIO() with smart_open.smart_open('s3://dev-test/bar/foo.csv', 'wb') as fout: writer = csv.DictWriter(f, fieldnames=fieldnames) writer.writeheader() fout.write(f.getvalue()) for row in testDict: f.seek(0) f.truncate(0) writer.writerow(row) fout.write(f.getvalue()) f.close() 方法。

答案 1 :(得分:0)

那是因为这总是指它的父亲,现在是这个功能。所以,如果你想要,你可以这样做:

-(void)createCollisionAreas
{
    if (_tileMap)
    {
        TMXObjectGroup *group = [_tileMap groupNamed:@"ContactZone"]; //Layer's name.

        //Province gateway.
        NSDictionary *singularObject = [group objectNamed:@"msgDifferentProvince"];
        if (singularObject)
        {
            CGFloat x = [singularObject[@"x"] floatValue];
            CGFloat y = [singularObject[@"y"] floatValue];
            CGFloat w = [singularObject[@"width"] floatValue];
            CGFloat h = [singularObject[@"height"] floatValue];

            SKSpriteNode *object = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(w, h)];
            object.name = @"provinceGateway";
            object.position = CGPointMake(x + w/2, y + h/2);

            object.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(w, h)];

            object.physicsBody.categoryBitMask       = terrainCategory;
            object.physicsBody.contactTestBitMask    = playerCategory;
            object.physicsBody.collisionBitMask      = 0;
            object.physicsBody.dynamic = NO;
            object.physicsBody.friction = 0;
            object.hidden = YES;

            [_backgroundLayer addChild:object];
        }

        /*More code written below. Too lazy to copy & paste it all*/
}

-(void)didBeginContact:(SKPhysicsContact *)contact
{
    SKPhysicsBody *firstBody, *secondBody; //Create 2 placeholder reference's for the contacting objects.

    if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask) //If bodyA has smallest of 2 bits...
    {
        firstBody   = contact.bodyA; //...it is then the firstBody reference [Smallest of two (category) bits.].
        secondBody  = contact.bodyB; //...and bodyB is then secondBody reference [Largest of two bits.].
    }
    else //This is the reverse of the above code (just in case so we always know what's what).
    {
        firstBody = contact.bodyB;
        secondBody = contact.bodyA;
    }


    /**BOUNDARY contacts*/
    if ((firstBody.categoryBitMask == noGoCategory) && (secondBody.categoryBitMask == playerCategory))
    {
        //Boundary contacted by player.
        if ([_backgroundLayer childNodeWithName:@"bounds"])
        {
            NSLog(@"Player contacted map bounds.");
        }
        if ([_backgroundLayer childNodeWithName:@"nogo"])
        {
            NSLog(@"Player can't go further.");
        }
        if ([_backgroundLayer childNodeWithName:@"provinceGateway"])
        {
            NSLog(@"Another province is ahead. Can't go any further.");
        }
        if ([_backgroundLayer childNodeWithName:@"slope"])
        {
            NSLog(@"Player contacted a slope.");
        }
}

答案 2 :(得分:0)

你可以重新绑定这个变量:     this.Scope.$on("$routeChangeSuccessEvent",this.onRouteChangeStart.bind(this));

答案 3 :(得分:0)

如其他解决方案中所述,并至少使用TypeScript v1.7,您可以使用如下的胖箭头来使用它:

$scope.$on('some-event', () => { console.log('here `this` is not undefined'); });
$scope.$watch('foo.bar', (a,b) => { console.log('here too...'); }
$scope.$on('$routeChangeSuccessEvent', () => { console.log('here too...'); });

但是,如果要从同一个类传递对函数的引用,则必须使用.bind(this)表示法:

$cope.$on('$routeChangeSuccessEvent', this.onRouteChangeStart.bind(this));