Skip to content

Commit 33fe0a2

Browse files
committed
uiGridOneBindClass now supports lists and object defs
Fixes a problem where uiGridOneBindClass would throw errors when passing an object as a parameter. Also now supports lists. The values in the object passed to uiGridOneBind must not be null or undefined for it to remove the watcher.
1 parent ce65ca1 commit 33fe0a2

File tree

2 files changed

+160
-60
lines changed

2 files changed

+160
-60
lines changed

src/js/core/directives/ui-grid-one-bind.js

Lines changed: 86 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@
7272
* @element div
7373
* @restrict A
7474
* @param {String} uiGridOneBindClass The angular string you want to bind. Does not support interpolation. Don't use <code>{{scopeElt}}</code> instead use <code>scopeElt</code>.
75+
* @param {Object} uiGridOneBindClass The object that you want to bind. At least one of the values in the object must be something other than null or undefined for the watcher to be removed.
76+
* this is to prevent the watcher from being removed before the scope is initialized.
77+
* @param {Array} uiGridOneBindClass An array of classes to bind to this element.
7578
* @description One time binding for the class dom tag. For more information see {@link ui.grid.directive:uiGridOneBind}.
7679
*/
7780
{tag: 'Class', method: 'addClass'},
@@ -208,75 +211,98 @@
208211
return {
209212
restrict: 'A',
210213
require: ['?uiGrid','?^uiGrid'],
211-
compile: function compile(tElement, tAttrs, transclude) {
212-
return {
213-
post: function(scope, iElement, iAttrs, controllers){
214-
/* Appends the grid id to the beginnig of the value. */
215-
var appendGridId = function(val){
216-
var grid; //Get an instance of the grid if its available
217-
//If its available in the scope then we don't need to try to find it elsewhere
218-
if (scope.grid) {
219-
grid = scope.grid;
220-
}
221-
//Another possible location to try to find the grid
222-
else if (scope.col && scope.col.grid){
223-
grid = scope.col.grid;
224-
}
225-
//Last ditch effort: Search through the provided controllers.
226-
else if (!controllers.some( //Go through the controllers till one has the element we need
227-
function(controller){
228-
if (controller && controller.grid) {
229-
grid = controller.grid;
230-
return true; //We've found the grid
231-
}
232-
})){
233-
//We tried our best to find it for you
234-
gridUtil.logError("["+directiveName+"] A valid grid could not be found to bind id. Are you using this directive " +
235-
"within the correct scope? Trying to generate id: [gridID]-" + val);
236-
throw new Error("No valid grid could be found");
214+
link: function(scope, iElement, iAttrs, controllers){
215+
/* Appends the grid id to the beginnig of the value. */
216+
var appendGridId = function(val){
217+
var grid; //Get an instance of the grid if its available
218+
//If its available in the scope then we don't need to try to find it elsewhere
219+
if (scope.grid) {
220+
grid = scope.grid;
221+
}
222+
//Another possible location to try to find the grid
223+
else if (scope.col && scope.col.grid){
224+
grid = scope.col.grid;
225+
}
226+
//Last ditch effort: Search through the provided controllers.
227+
else if (!controllers.some( //Go through the controllers till one has the element we need
228+
function(controller){
229+
if (controller && controller.grid) {
230+
grid = controller.grid;
231+
return true; //We've found the grid
237232
}
233+
})){
234+
//We tried our best to find it for you
235+
gridUtil.logError("["+directiveName+"] A valid grid could not be found to bind id. Are you using this directive " +
236+
"within the correct scope? Trying to generate id: [gridID]-" + val);
237+
throw new Error("No valid grid could be found");
238+
}
238239

239-
if (grid){
240-
var idRegex = new RegExp(grid.id.toString());
241-
//If the grid id hasn't been appended already in the template declaration
242-
if (!idRegex.test(val)){
243-
val = grid.id.toString() + '-' + val;
244-
}
245-
}
246-
return val;
247-
};
240+
if (grid){
241+
var idRegex = new RegExp(grid.id.toString());
242+
//If the grid id hasn't been appended already in the template declaration
243+
if (!idRegex.test(val)){
244+
val = grid.id.toString() + '-' + val;
245+
}
246+
}
247+
return val;
248+
};
248249

250+
// The watch returns a function to remove itself.
251+
var rmWatcher = scope.$watch(iAttrs[directiveName], function(newV){
252+
if (newV){
253+
//If we are trying to add an id element then we also apply the grid id if it isn't already there
254+
if (v.appendGridId) {
255+
var newIdString = null;
256+
//Append the id to all of the new ids.
257+
angular.forEach( newV.split(' '), function(s){
258+
newIdString = (newIdString ? (newIdString + ' ') : '') + appendGridId(s);
259+
});
260+
newV = newIdString;
261+
}
249262

250-
var rmWatcher = scope.$watch(iAttrs[directiveName], function(newV,oldV){
251-
if (newV) {
252-
//If we are trying to add an id element then we also apply the grid id if it isn't already there
253-
if (v.appendGridId) {
254-
var newIdString = null;
255-
//Append the id to all of the new ids.
256-
angular.forEach( newV.split(' '), function(s){
257-
newIdString = (newIdString ? (newIdString + ' ') : '') + appendGridId(s);
263+
// Append this newValue to the dom element.
264+
switch (v.method) {
265+
case 'attr': //The attr method takes two paraams the tag and the value
266+
if (v.aria) {
267+
//If it is an aria element then append the aria prefix
268+
iElement[v.method]('aria-' + v.tag.toLowerCase(),newV);
269+
} else {
270+
iElement[v.method](v.tag.toLowerCase(),newV);
271+
}
272+
break;
273+
case 'addClass':
274+
//Pulled from https://github.com/Pasvaz/bindonce/blob/master/bindonce.js
275+
if (angular.isObject(newV) && !angular.isArray(newV)) {
276+
var results = [];
277+
var nonNullFound = false; //We don't want to remove the binding unless the key is actually defined
278+
angular.forEach(newV, function (value, index) {
279+
if (value !== null && typeof(value) !== "undefined"){
280+
nonNullFound = true; //A non null value for a key was found so the object must have been initialized
281+
if (value) {results.push(index);}
282+
}
258283
});
259-
newV = newIdString;
284+
//A non null value for a key wasn't found so assume that the scope values haven't been fully initialized
285+
if (!nonNullFound){
286+
return; // If not initialized then the watcher should not be removed yet.
287+
}
288+
newV = results;
260289
}
261290

262-
// Append this newValue to the dom element.
263-
if (v.method === 'attr') {
264-
//The attr method takes two paraams the tag and the value
265-
if (v.aria) {
266-
//If it is an aria element then append the aria prefix
267-
iElement[v.method]('aria-' + v.tag.toLowerCase(),newV);
268-
} else {
269-
iElement[v.method](v.tag.toLowerCase(),newV);
270-
}
291+
if (newV) {
292+
iElement.addClass(angular.isArray(newV) ? newV.join(' ') : newV);
271293
} else {
272-
iElement[v.method](newV);
294+
return;
273295
}
274-
//Removes the watcher on itself after the bind
275-
rmWatcher();
276-
}
277-
}); //End rm watchers
278-
} // End post function
279-
}; // End compile return
296+
break;
297+
default:
298+
iElement[v.method](newV);
299+
break;
300+
}
301+
302+
//Removes the watcher on itself after the bind
303+
rmWatcher();
304+
}
305+
}); //End rm watchers
280306
} //End compile function
281307
}; //End directive return
282308
} // End directive function

test/unit/core/directives/ui-grid-one-bind.spec.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,77 @@ angular.forEach([
134134
});
135135
});
136136
});
137+
138+
describe('ui-grid-one-bind-class', function() {
139+
var $scope, $compile, directiveElt, recompile;
140+
141+
beforeEach(module('ui.grid'));
142+
143+
//Try out two different starting values
144+
angular.forEach([null, undefined], function(startingValue){
145+
describe("basic 'class' one bind using object with starting value '" + startingValue + "'", function(){
146+
beforeEach(inject(function (_$compile_, $rootScope) {
147+
$scope = $rootScope;
148+
$compile = _$compile_;
149+
150+
//Initialize the value
151+
$scope.valNull = startingValue;
152+
153+
recompile = function () {
154+
directiveElt = angular.element("<div ui-grid-one-bind-class='{customClass: val}'></div>");
155+
$compile(directiveElt)($scope);
156+
$scope.$digest();
157+
};
158+
recompile();
159+
}));
160+
161+
it("should bind the value to the 'class' dom tag", function(){
162+
$scope.val = true;
163+
$scope.$digest();
164+
expect(directiveElt.hasClass('customClass')).toBe($scope.val);
165+
166+
});
167+
168+
it("should not change the 'class' after the watcher should have been removed", function(){
169+
$scope.val = true;
170+
$scope.$digest();
171+
$scope.val = false;
172+
$scope.$digest();
173+
expect(directiveElt.hasClass('customClass')).not.toBe($scope.val);
174+
});
175+
});
176+
});
177+
178+
describe("basic 'class' one bind using a variable", function(){
179+
beforeEach(inject(function (_$compile_, $rootScope) {
180+
$scope = $rootScope;
181+
$compile = _$compile_;
182+
183+
$scope.classElement = null;
184+
185+
recompile = function () {
186+
directiveElt = angular.element("<div ui-grid-one-bind-class='classElement'></div>");
187+
$compile(directiveElt)($scope);
188+
$scope.$digest();
189+
};
190+
recompile();
191+
192+
}));
193+
it("should have the classses listed", function(){
194+
$scope.classElement = ['customClass', 'anotherCustomClass'];
195+
196+
$scope.$digest();
197+
198+
expect(directiveElt.hasClass('customClass')).toBe(true);
199+
expect(directiveElt.hasClass('anotherCustomClass')).toBe(true);
200+
});
201+
it("should have the class listed", function(){
202+
$scope.classElement = 'customClass';
203+
204+
$scope.$digest();
205+
206+
expect(directiveElt.hasClass('customClass')).toBe(true);
207+
});
208+
});
209+
210+
});

0 commit comments

Comments
 (0)