Skip to content

Commit

Permalink
feat(comments): Instantiate configured controller for comments
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Caitlin Potter committed Sep 26, 2013
1 parent 9ca3ec7 commit 0739098
Show file tree
Hide file tree
Showing 2 changed files with 202 additions and 88 deletions.
71 changes: 62 additions & 9 deletions src/comments.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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() {
Expand All @@ -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;
});
};
Expand All @@ -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;
Expand Down
219 changes: 140 additions & 79 deletions src/test/comments.spec.js
Original file line number Diff line number Diff line change
@@ -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('<comments comment-data="comments"></comments>'))($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('<comments comment-data="comments"></comments>'))($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('<comments comment-data="comments"></comments>'))($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('<comments comment-data="comments"></comments>'))($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('<comments comment-data="comments"></comments>'))($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('<comments comment-data="comments"></comments>'))($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('<comments comment-data="comments"></comments>'))($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('<comments comment-data="comments"></comments>'))($scope);
$scope.$digest();
expect(children.find('.comment-body').first().text()).toEqual('Second child');
expect(comments.find('.comment').first().scope().controllerName).toEqual('TestCtrl4');
});
});
});

0 comments on commit 0739098

Please sign in to comment.