为什么我的$ watch不能在我的指令测试中工作 - Angularjs

时间:2013-12-09 14:46:09

标签: javascript angularjs

我有一个指令,我在其中传递attrs然后在指令中观察它。更改attrs后,就会发生动画。当attrs被触发时,我的$watch始终未定义。

App.directive('resize', function($animate) {
  return function(scope, element, attrs) {
    scope.$watch(attrs.resize, function(newVal) {
      if(newVal) {
        $animate.addClass(element, 'span8');
      }
    });
  };
});

这是我的测试:

describe('resize', function() {
  var element, scope;
  beforeEach(inject(function($compile, $rootScope) {
    var directive = angular.element('<div class="span12" resize="isHidden"></div>');
    element = $compile(directive)($rootScope);
    $rootScope.$digest();
    scope = $rootScope;
  }));

  it('should change to a span8 after resize', function() {
    expect($(element).hasClass('span12')).toBeTruthy();
    expect($(element).hasClass('span8')).toBeFalsy();
    element.attr('resize', 'true');
    element.scope().$apply();
    expect($(element).hasClass('span8')).toBeTruthy();
  });
});

attrs发生变化时,我的观察者newValue未定义,因此没有任何反应。我需要做些什么来完成这项工作?这是plunker

3 个答案:

答案 0 :(得分:1)

你没有看到attrs.resize的价值;您正在观察 attrs.resize所指向的值,而在测试用例中则是一个名为isHidden的范围成员。这不存在,因此undefined

对于您尝试做的事情,以下方法可行:

App.directive('resize', function($animate) {
    return function(scope, element, attrs) {
        scope.$watch(
            // NOTE THE DIFFERENCE HERE
            function() {
                return element.attr("resize");
// EDIT: Changed in favor of line above...
//              return attrs.resize;
            },
            function(newVal) {
                if(newVal) {
                    $animate.addClass(element, 'span8');
                }
            }
        );
    };
});

编辑:似乎attrs对象 NOT 从DOM更新中获取非内插值的更新。所以你必须看element.attr("resize")。我担心这不会有效...参见forked plunk:http://plnkr.co/edit/iBNpha33e2Xw8CHgWmVx?p=preview

答案 1 :(得分:0)

以下是我能够进行此测试的方法。我将变量作为attr传递给指令。变量名称为isHidden。这是我的测试,其中包含正在运行的更新代码。

describe('resize', function() {
  var element, scope;
  beforeEach(inject(function($compile, $rootScope) {
    var directive = angular.element('<div class="span12" resize="isHidden"></div>');
    element = $compile(directive)($rootScope);
    $rootScope.$digest();
    scope = $rootScope;
  }));

  it('should change to a span8 after resize', function() {
    expect($(element).hasClass('span12')).toBeTruthy();
    expect($(element).hasClass('span8')).toBeFalsy();
    element.scope().isHidden = true;
    scope.$apply();
    expect($(element).hasClass('span8')).toBeTruthy();
  });
});

我可以通过附加到isHidden的范围访问变量element。更改变量后,我必须运行$digest进行更新,然后全部变为黄金。

我觉得我应该像$observe所指出的那样使用package。我会看一下,并在我开始工作时添加评论。

答案 2 :(得分:0)

正如Nikos所指出的那样,问题在于你没有注意到attrs.resize的价值,所以你可以尝试这样做:

创建一个变量来保存数据并创建这些$ watch函数:

var dataGetter;

scope.$watch(function () {
    return attrs.resize;
}, function (newVal) {
    dataGetter = $parse(newVal);
});

scope.$watch(function () {
    return dataGetter && dataGetter(scope);
}, function (newVal) {
    // Do stuff here         
});

这里应该发生的是Angular的$parse函数应该评估attrs.resize并返回类似this的函数。然后你将范围传递给它并做一些事情。只要attrs.resize只是一个布尔值,那么第二个监视表达式中的newVal应该是一个布尔值,我希望。