Skip to content
This repository was archived by the owner on Oct 22, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions src/bindNotifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,19 @@
* @returns {Function} wrap - A decorated oneTimeWatchDelegate function.
*/
function dynamicWatcher (expr, notifierKeys) {
function setupListeners (scope, cb) {
notifierKeys.forEach(function (nk) {
scope.$on('$$rebind::' + nk, cb);
});
}

function wrap (watchDelegate, scope, listener, objectEquality, parsedExpression) {
var delegateCall = watchDelegate.bind(this, scope, listener, objectEquality, parsedExpression);

notifierKeys.forEach(function (n) {
scope.$on('$$rebind::' + n, delegateCall);
});
// In a nutshell; If of type 'oneTimeWatchDelegate', add $on listeners.
if (/oneTimeWatchDelegate/.test(watchDelegate.toString())) {
setupListeners(scope, delegateCall);
}

delegateCall();
}
Expand Down
60 changes: 48 additions & 12 deletions test/bindNotifier.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
'use strict';

describe('bindNotifier {Directive}', function () {
var $scope, el, span, createEl, run, broadcaster;
var $scope, $compile, el, span, createEl, run, broadcaster;

beforeEach(function () {
module('angular.bind.notifier');

inject(function ($compile, $rootScope) {
$scope = $rootScope.$new();
inject(function ($injector) {
$scope = $injector.get('$rootScope').$new();
$compile = $injector.get('$compile');

createEl = function (exprObjs, expression) {
exprObjs = exprObjs || [];
Expand Down Expand Up @@ -124,34 +125,69 @@
expect(broadcaster).to.have.been.calledOnce.and.calledWith('$$rebind::k1');
});

context('object expression', function() {
context('when terse', function() {
context('object expression', function () {
context('when terse', function () {
expectBothSingleAndMultiple('{value:dummy}.value');
});
context('when spaces are present', function() {
context('when spaces are present', function () {
expectBothSingleAndMultiple(' { value : dummy }.value ');
});
});

context('array expression', function() {
context('when terse', function() {
context('array expression', function () {
context('when terse', function () {
expectBothSingleAndMultiple('[null,{value:dummy}][1].value');
});
context('when spaces are present', function() {
context('when spaces are present', function () {
expectBothSingleAndMultiple(' [ null , { value: dummy } ][1].value ');
});
});

function expectBothSingleAndMultiple(expression) {
it('handles a single notifier key', function() {
context('directive compatibility', function () {
var dirs = [
'ng-class', 'ng-hide', 'ng-show', 'ng-bind', 'ng-if',
'ng-class-even', 'ng-class-odd', 'ng-pattern'
];

dirs.forEach(function (dir) {
it(dir + ' does not increase $$listener count exponentially', function () {
$scope.items = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
var dom = '<div>' +
'<span ng-repeat="i in :f:items" ' + dir + '=":f:i">{{:f:i}}</span>' +
'</div>';

dom = $compile(dom)($scope);
$scope.$digest();

$scope.$broadcast('$$rebind::f');
$scope.$digest();

$scope.$broadcast('$$rebind::f');
$scope.$digest();

$scope.$broadcast('$$rebind::f');
$scope.$digest();

$scope.$broadcast('$$rebind::f');
$scope.$digest();

var totalCount = $scope.$$listenerCount['$$rebind::f'];

expect(totalCount).to.eq($scope.items.length * 2 + 1);
});
});
});

function expectBothSingleAndMultiple (expression) {
it('handles a single notifier key', function () {
createEl([{ k1: 'k1Expr' }], expression);

$scope.dummy = 'glenn';
run('k1Expr');

expect(span.innerText).to.equal('glenn');
});
it('handles several notifier keys', function() {
it('handles several notifier keys', function () {
createEl([{ k1: 'k1Expr' }, { k2: 'k2Expr' }], expression);

$scope.dummy = 1;
Expand Down