Skip to content

Commit

Permalink
feat(ncyBreadcrumb): watch every expression founded in labels
Browse files Browse the repository at this point in the history
In somes cases, the breadcrumb has to be updated without changing the state. A `$viewContentLoaded` can be trigged manually but this implementation of the feature causes no overhead for the developper.

There is one watcher created for each expression in each labels. All watchers are deregistered before breadcrumb's updates.
  • Loading branch information
ncuillery committed Jun 17, 2014
1 parent 7994afb commit 1363515
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 12 deletions.
49 changes: 41 additions & 8 deletions dist/angular-breadcrumb.js
@@ -1,4 +1,4 @@
/*! angular-breadcrumb - v0.2.1-dev-2014-06-13
/*! angular-breadcrumb - v0.2.1-dev-2014-06-18
* https://github.com/ncuillery/angular-breadcrumb
* Copyright (c) 2014 Nicolas Cuillery; Licensed MIT */

Expand Down Expand Up @@ -29,7 +29,6 @@ function $Breadcrumb() {

// Early catch of $viewContentLoaded event
$rootScope.$on('$viewContentLoaded', function (event) {
console.log('listener service');
// With nested views, the event occur several times, in "wrong" order
if(isAOlderThanB(event.targetScope.$id, $lastViewScope.$id)) {
$lastViewScope = event.targetScope;
Expand Down Expand Up @@ -177,22 +176,56 @@ function BreadcrumbDirective($interpolate, $breadcrumb, $rootScope) {
templateUrl: $breadcrumb.getTemplateUrl(),
link: {
post: function postLink(scope) {
var labelWatchers = [];

var getExpression = function(interpolationFunction) {
if(interpolationFunction.expressions) {
return interpolationFunction.expressions;
} else {
var expressions = [];
angular.forEach(interpolationFunction.parts, function(part) {
if(angular.isFunction(part)) {
expressions.push(part.exp);
}
});
return expressions;
}
};

var registerWatchers = function(interpolationFunction, scope, step) {
angular.forEach(getExpression(interpolationFunction), function(expression) {
var watcher = scope.$watch(expression, function() {
step.ncyBreadcrumbLabel = interpolationFunction(scope);
});
labelWatchers.push(watcher);
});

};

var deregisterWatchers = function() {
angular.forEach(labelWatchers, function(deregisterWatch) {
deregisterWatch();
});
labelWatchers = [];
};

var renderBreadcrumb = function() {
deregisterWatchers();
var viewScope = $breadcrumb.$getLastViewScope();
scope.steps = $breadcrumb.getStatesChain();
angular.forEach(scope.steps, function (value) {
if (value.data && value.data.ncyBreadcrumbLabel) {
var parseLabel = $interpolate(value.data.ncyBreadcrumbLabel);
value.ncyBreadcrumbLabel = parseLabel(viewScope);
angular.forEach(scope.steps, function (step) {
if (step.data && step.data.ncyBreadcrumbLabel) {
var parseLabel = $interpolate(step.data.ncyBreadcrumbLabel);
step.ncyBreadcrumbLabel = parseLabel(viewScope);
// Watcher for further viewScope updates
registerWatchers(parseLabel, viewScope, step);
} else {
value.ncyBreadcrumbLabel = value.name;
step.ncyBreadcrumbLabel = step.name;
}
});
};

$rootScope.$on('$viewContentLoaded', function () {
console.log('listener directive');
renderBreadcrumb();
});

Expand Down
4 changes: 2 additions & 2 deletions dist/angular-breadcrumb.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 35 additions & 2 deletions src/angular-breadcrumb.js
Expand Up @@ -24,7 +24,6 @@ function $Breadcrumb() {

// Early catch of $viewContentLoaded event
$rootScope.$on('$viewContentLoaded', function (event) {
console.log('listener service');
// With nested views, the event occur several times, in "wrong" order
if(isAOlderThanB(event.targetScope.$id, $lastViewScope.$id)) {
$lastViewScope = event.targetScope;
Expand Down Expand Up @@ -172,22 +171,56 @@ function BreadcrumbDirective($interpolate, $breadcrumb, $rootScope) {
templateUrl: $breadcrumb.getTemplateUrl(),
link: {
post: function postLink(scope) {
var labelWatchers = [];

var getExpression = function(interpolationFunction) {
if(interpolationFunction.expressions) {
return interpolationFunction.expressions;
} else {
var expressions = [];
angular.forEach(interpolationFunction.parts, function(part) {
if(angular.isFunction(part)) {
expressions.push(part.exp);
}
});
return expressions;
}
};

var registerWatchers = function(interpolationFunction, scope, step) {
angular.forEach(getExpression(interpolationFunction), function(expression) {
var watcher = scope.$watch(expression, function() {
step.ncyBreadcrumbLabel = interpolationFunction(scope);
});
labelWatchers.push(watcher);
});

};

var deregisterWatchers = function() {
angular.forEach(labelWatchers, function(deregisterWatch) {
deregisterWatch();
});
labelWatchers = [];
};

var renderBreadcrumb = function() {
deregisterWatchers();
var viewScope = $breadcrumb.$getLastViewScope();
scope.steps = $breadcrumb.getStatesChain();
angular.forEach(scope.steps, function (value) {
if (value.data && value.data.ncyBreadcrumbLabel) {
var parseLabel = $interpolate(value.data.ncyBreadcrumbLabel);
value.ncyBreadcrumbLabel = parseLabel(viewScope);
// Watcher for further viewScope updates
registerWatchers(parseLabel, viewScope, value);
} else {
value.ncyBreadcrumbLabel = value.name;
}
});
};

$rootScope.$on('$viewContentLoaded', function () {
console.log('listener directive');
renderBreadcrumb();
});

Expand Down
20 changes: 20 additions & 0 deletions test/spec/directive-interpolation-test.js
Expand Up @@ -31,4 +31,24 @@ describe('Directive with interpolation conf', function() {
expect(element.text()).toContain('State BBB');
}));

it('deals with further updates of the scope', inject(function() {
goToState('A.B');

controller('BCtrl', {'$scope' : scope} );
compile(scope);

scope.$emit('$viewContentLoaded');
scope.$digest();

console.info('Directive content : ' + element.text());

expect(element.text()).toContain('State BBB');

scope.tripleB = 'HACKED';
scope.$digest();

expect(element.text()).toContain('State HACKED');

}));

});

0 comments on commit 1363515

Please sign in to comment.