From 07390982172e8ea1a5a956b8c3362aa45bca2d7f Mon Sep 17 00:00:00 2001 From: Caitlin Potter Date: Wed, 25 Sep 2013 22:08:31 -0400 Subject: [PATCH] feat(comments): Instantiate configured controller for comments I've added a couple of tests for this and it seems to be working nicely. Additionally, I'm also returning the templateUrl from a function, so this should hopefully be more dynamic as well. I'll need to add some tests for that, though. --- src/comments.js | 71 ++++++++++-- src/test/comments.spec.js | 219 ++++++++++++++++++++++++-------------- 2 files changed, 202 insertions(+), 88 deletions(-) diff --git a/src/comments.js b/src/comments.js index 35453a5..49b562c 100644 --- a/src/comments.js +++ b/src/comments.js @@ -10,10 +10,48 @@ angular.module('ui.comments.directive', []) // url The URL for a user profile // -.constant('commentsConfig', { - containerTemplate: 'template/comments/comments.html', - commentTemplate: 'template/comments/comment.html', - orderBy: 'best' +.provider('commentsConfig', function() { + var config = { + containerTemplate: 'template/comments/comments.html', + commentTemplate: 'template/comments/comment.html', + orderBy: 'best', + commentController: undefined + }; + var emptyController = function() {}; + function stringSetter(setting, value) { + if (typeof value === 'string') { + config[setting] = value; + } + } + function controllerSetter(setting, value) { + if (value && typeof value === 'string' || + typeof value === 'function' || + angular.isArray(value)) { + config[setting] = value; + } else { + config[setting] = emptyController; + } + } + + var setters = { + 'containerTemplate': stringSetter, + 'commentTemplate': stringSetter, + 'orderBy': stringSetter, + 'commentController': controllerSetter + }; + this.$get = function() { + return config; + }; + this.set = function(name, value) { + if (typeof name === 'string') { + var fn = setters[name]; + if (fn) { + fn(name, value); + } + } else if (typeof name === 'object') { + angular.forEach(name, this.set); + } + }; }) .directive('comments', function($compile, commentsConfig) { @@ -22,7 +60,7 @@ angular.module('ui.comments.directive', []) require: '?^comment', transclude: true, replace: true, - templateUrl: commentsConfig.containerTemplate, + templateUrl: function() { return commentsConfig.containerTemplate; }, scope: true, controller: function($scope) {}, compile: function() { @@ -32,7 +70,7 @@ angular.module('ui.comments.directive', []) scope.$watchCollection(attr.commentData, function(newval, oldval) { scope.self.commentData = angular.isArray(newval) ? newval : []; }); - scope.$watch(attr.orderBy, function(newval, oldval) { + attr.$observe('orderBy', function(newval, oldval) { scope.self.commentOrder = newval || commentsConfig.orderBy; }); }; @@ -46,15 +84,30 @@ angular.module('ui.comments.directive', []) restrict: 'EA', transclude: true, replace: true, - templateUrl: commentsConfig.commentTemplate, - compile: function() { + templateUrl: function() { return commentsConfig.commentTemplate; }, + controller: function($scope, $controller, commentsConfig) { + var unregister = $scope.$watch('$element', function($element) { + unregister(); + unregister = undefined; + $scope.$element = undefined; + var controller = commentsConfig.commentController, + controllerInstance; + if (controller) { + controllerInstance = $controller(controller, { + '$scope': $scope + }); + $element.data('$commentController', controllerInstance); + } + }); + }, + compile: function(scope, elem) { return function(scope, elem, attr, comments) { if (elem.parent().attr('child-comments') === 'true') { elem.addClass('child-comment'); } scope.comment = scope.$eval(attr.commentData); var children = false; - + scope.$element = elem; function update(data) { if (angular.isArray(data) && data.length > 0 && !children) { var e = angular.element; diff --git a/src/test/comments.spec.js b/src/test/comments.spec.js index f214172..c4f50ae 100644 --- a/src/test/comments.spec.js +++ b/src/test/comments.spec.js @@ -1,105 +1,166 @@ describe('ui.comments', function() { var $scope, $document, $body, $compile, comments; - beforeEach(function() { - angular.forEach([ - 'ui.comments.directive', - 'template/comments/comments.html', - 'template/comments/comment.html', - ], function(m) { - module(m); - }); - - inject(function(_$rootScope_, _$document_, _$compile_) { - $scope = _$rootScope_; - $document = _$document_; - $compile = _$compile_; - $body = $document.find('body'); - }); - }); - describe('top-level comments', function() { + describe('DOM', function() { beforeEach(function() { - $scope.comments = []; - comments = $compile(angular.element(''))($scope); + angular.forEach([ + 'ui.comments.directive', + 'template/comments/comments.html', + 'template/comments/comment.html', + ], function(m) { + module(m); + }); + + inject(function(_$rootScope_, _$document_, _$compile_) { + $scope = _$rootScope_; + $document = _$document_; + $compile = _$compile_; + $body = $document.find('body'); + }); }); - it('adds comment to DOM when comment model grows', function() { - expect(comments.children().length).toEqual(0); - $scope.comments.push({}); - $scope.$digest(); - expect(comments.children().length).toEqual(1); - }); + describe('top-level comments', function() { + beforeEach(function() { + $scope.comments = []; + comments = $compile(angular.element(''))($scope); + }); - it('removes comment from DOM when comment model shrinks', function() { - $scope.comments.push({}); - $scope.$digest(); - expect(comments.children().length).toEqual(1); - $scope.comments.pop(); - $scope.$digest(); - expect(comments.children().length).toEqual(0); - }); + it('adds comment to DOM when comment model grows', function() { + expect(comments.children().length).toEqual(0); + $scope.comments.push({}); + $scope.$digest(); + expect(comments.children().length).toEqual(1); + }); - it('changes comment data when comment model changes', function() { - $scope.comments.push({text: 'Test Comment'}); - $scope.$digest(); - expect(comments.find('.comment-body').text()).toEqual("Test Comment"); - $scope.comments[0].text = 'Changed Comment'; - $scope.$digest(); - expect(comments.find('.comment-body').text()).toEqual("Changed Comment"); + it('removes comment from DOM when comment model shrinks', function() { + $scope.comments.push({}); + $scope.$digest(); + expect(comments.children().length).toEqual(1); + $scope.comments.pop(); + $scope.$digest(); + expect(comments.children().length).toEqual(0); + }); + + it('changes comment data when comment model changes', function() { + $scope.comments.push({text: 'Test Comment'}); + $scope.$digest(); + expect(comments.find('.comment-body').text()).toEqual("Test Comment"); + $scope.comments[0].text = 'Changed Comment'; + $scope.$digest(); + expect(comments.find('.comment-body').text()).toEqual("Changed Comment"); + }); + + it('re-orders comments in DOM when comment model is re-ordered', function() { + $scope.comments.push({text: '123'}); + $scope.comments.push({text: 'ABC'}); + $scope.$digest(); + expect(comments.find('.comment-body').first().text()).toEqual('123'); + $scope.comments.reverse(); + $scope.$digest(); + expect(comments.find('.comment-body').first().text()).toEqual('ABC'); + }); }); - it('re-orders comments in DOM when comment model is re-ordered', function() { - $scope.comments.push({text: '123'}); - $scope.comments.push({text: 'ABC'}); - $scope.$digest(); - expect(comments.find('.comment-body').first().text()).toEqual('123'); - $scope.comments.reverse(); - $scope.$digest(); - expect(comments.find('.comment-body').first().text()).toEqual('ABC'); + describe('child comments', function() { + beforeEach(function() { + $scope.comments = [{ + text: 'Comment level 1', + children: [ + { text: 'First child' }, + { text: 'Second child' } + ] + }]; + comments = $compile(angular.element(''))($scope); + $scope.$digest(); + }); + + it('adds comment to DOM when child comment model grows', function() { + expect(comments.find('.child-comment').length).toEqual(2); + $scope.comments[0].children.push({text: 'Test'}); + $scope.$digest(); + expect(comments.find('.child-comment').length).toEqual(3); + }); + + it('removes comment from DOM when child comment model shrinks', function() { + expect(comments.find('.child-comment').length).toEqual(2); + $scope.comments[0].children.pop(); + $scope.$digest(); + expect(comments.find('.child-comment').length).toEqual(1); + }); + + it('changes comment data when child comment model changes', function() { + var first = comments.find('.child-comment > .comment-body').first(); + expect(first.text()).toEqual("First child"); + $scope.comments[0].children[0].text = 'Changed Comment'; + $scope.$digest(); + expect(first.text()).toEqual("Changed Comment"); + }); + + it('re-orders comments in DOM when child comment model is re-ordered', function() { + var children = comments.find('.child-comment'); + expect(children.find('.comment-body').first().text()).toEqual('First child'); + $scope.comments[0].children.reverse(); + $scope.$digest(); + expect(children.find('.comment-body').first().text()).toEqual('Second child'); + }); }); }); - describe('child comments', function() { + describe('custom comment controller', function() { + var app, commentsConfig; beforeEach(function() { - $scope.comments = [{ - text: 'Comment level 1', - children: [ - { text: 'First child' }, - { text: 'Second child' } - ] - }]; - comments = $compile(angular.element(''))($scope); - $scope.$digest(); + app = angular.module('customController', ['ui.comments.directive']) + .controller('TestCtrl1', function($scope) { + $scope.controllerName = "TestCtrl1"; + }) + .controller('TestCtrl2', function($scope) { + $scope.controllerName = "TestCtrl2"; + }); + angular.forEach([ + 'customController', + 'template/comments/comments.html', + 'template/comments/comment.html', + ], function(m) { + module(m); + }); + + inject(function(_$rootScope_, _$document_, _$compile_, _commentsConfig_) { + $scope = _$rootScope_; + $document = _$document_; + $compile = _$compile_; + $body = $document.find('body'); + commentsConfig = _commentsConfig_; + }); + $scope.comments = [{}]; }); - it('adds comment to DOM when child comment model grows', function() { - expect(comments.find('.child-comment').length).toEqual(2); - $scope.comments[0].children.push({text: 'Test'}); + it('instantiates the controller named in commentConfig', function() { + commentsConfig.commentController = 'TestCtrl1'; + comments = $compile(angular.element(''))($scope); $scope.$digest(); - expect(comments.find('.child-comment').length).toEqual(3); + expect(comments.find('.comment').first().scope().controllerName).toEqual('TestCtrl1'); }); - - it('removes comment from DOM when child comment model shrinks', function() { - expect(comments.find('.child-comment').length).toEqual(2); - $scope.comments[0].children.pop(); + it('instantiates the controller named in commentConfig', function() { + commentsConfig.commentController = 'TestCtrl2'; + comments = $compile(angular.element(''))($scope); $scope.$digest(); - expect(comments.find('.child-comment').length).toEqual(1); + expect(comments.find('.comment').first().scope().controllerName).toEqual('TestCtrl2'); }); - - it('changes comment data when child comment model changes', function() { - var first = comments.find('.child-comment > .comment-body').first(); - expect(first.text()).toEqual("First child"); - $scope.comments[0].children[0].text = 'Changed Comment'; + it('instantiates the controller function in commentConfig', function() { + commentsConfig.commentController = function($scope) { + $scope.controllerName = 'TestCtrl3'; + }; + comments = $compile(angular.element(''))($scope); $scope.$digest(); - expect(first.text()).toEqual("Changed Comment"); + expect(comments.find('.comment').first().scope().controllerName).toEqual('TestCtrl3'); }); - - it('re-orders comments in DOM when child comment model is re-ordered', function() { - var children = comments.find('.child-comment'); - expect(children.find('.comment-body').first().text()).toEqual('First child'); - $scope.comments[0].children.reverse(); + it('instantiates the controller function in commentConfig with bracket notation', function() { + commentsConfig.commentController = ['$scope', function(s) { + s.controllerName = 'TestCtrl4'; + }]; + comments = $compile(angular.element(''))($scope); $scope.$digest(); - expect(children.find('.comment-body').first().text()).toEqual('Second child'); + expect(comments.find('.comment').first().scope().controllerName).toEqual('TestCtrl4'); }); }); });