Skip to content

Commit e9cd802

Browse files
committed
fix(ng:options): compile null/blank option tag
Fixes angular#562
1 parent fd822bd commit e9cd802

File tree

3 files changed

+89
-3
lines changed

3 files changed

+89
-3
lines changed

src/Compiler.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,15 @@ Template.prototype = {
3333
paths = this.paths,
3434
length = paths.length;
3535
for (i = 0; i < length; i++) {
36-
children[i].link(jqLite(childNodes[paths[i]]), childScope);
36+
// sometimes `element` can be modified by one of the linker functions in `this.linkFns`
37+
// and childNodes may be added or removed
38+
// TODO: element structure needs to be re-evaluated if new children added
39+
// if the childNode still exists
40+
if (childNodes[paths[i]])
41+
children[i].link(jqLite(childNodes[paths[i]]), childScope);
42+
else
43+
// if child no longer available, delete path
44+
delete paths[i];
3745
}
3846
},
3947

src/widget/select.js

+13-2
Original file line numberDiff line numberDiff line change
@@ -243,9 +243,12 @@ angularWidget('select', function(element){
243243

244244
// find existing special options
245245
forEach(selectElement.children(), function(option){
246-
if (option.value == '')
246+
var opt;
247+
if (option.value == '') {
248+
opt = jqLite(option);
247249
// User is allowed to select the null.
248-
nullOption = {label:jqLite(option).text(), id:''};
250+
nullOption = {label:opt.text(), id:'', bindTemplate: opt.attr('ng:bind-template')};
251+
}
249252
});
250253
selectElement.html(''); // clear contents
251254

@@ -397,6 +400,14 @@ angularWidget('select', function(element){
397400
.val(option.id)
398401
.attr('selected', option.selected)
399402
.text(option.label);
403+
404+
// if it's a nullOption, compile it
405+
if (option.id === '') {
406+
if (option.bindTemplate)
407+
element.attr('ng:bind-template', option.bindTemplate);
408+
compile(element)(modelScope);
409+
}
410+
400411
existingOptions.push(existingOption = {
401412
element: element,
402413
label: option.label,

test/widget/selectSpec.js

+67
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,73 @@ describe('select', function() {
429429
expect(select.find('option').length).toEqual(1);
430430
});
431431
});
432+
433+
describe('blank option', function () {
434+
435+
function createSelect(attrs, blank, unknown){
436+
var html = '<select';
437+
forEach(attrs, function(value, key){
438+
if (isBoolean(value)) {
439+
if (value) html += ' ' + key;
440+
} else {
441+
html += ' ' + key + '="' + value + '"';
442+
}
443+
});
444+
html += '>' +
445+
(blank ? blank : '') +
446+
(unknown ? unknown : '') +
447+
'</select>';
448+
select = jqLite(html);
449+
scope = compile(select);
450+
}
451+
452+
function createSingleSelect(blank, unknown){
453+
createSelect({
454+
'ng:model':'selected',
455+
'ng:options':'value.name for value in values'
456+
}, blank, unknown);
457+
}
458+
459+
it('should be compiled as template, be watched and updated', function () {
460+
var option;
461+
462+
createSingleSelect('<option value="">blank is {{blankTemplate}}</option>');
463+
scope.blankTemplate = 'so blank';
464+
scope.values = [{name:'A'}];
465+
scope.$digest();
466+
467+
// check blank option is first and is compiled
468+
expect(select.find('option').length == 2);
469+
option = jqLite(select.find('option')[0]);
470+
expect(option.val()).toBe('');
471+
expect(option.text()).toBe('blank is so blank');
472+
473+
// change blankTemplate and $digest
474+
scope.blankTemplate = 'not so blank';
475+
scope.$digest();
476+
477+
// check blank option is first and is compiled
478+
expect(select.find('option').length == 2);
479+
option = jqLite(select.find('option')[0]);
480+
expect(option.val()).toBe('');
481+
expect(option.text()).toBe('blank is not so blank');
482+
});
483+
484+
it('should be compiled from ng:bind-template attribute if given instead of text', function () {
485+
var option;
486+
487+
createSingleSelect('<option value="" ng:bind-template="blank is {{blankTemplate}}"></option>');
488+
scope.blankTemplate = 'so blank';
489+
scope.values = [{name:'A'}];
490+
scope.$digest();
491+
492+
// check blank option is first and is compiled
493+
expect(select.find('option').length == 2);
494+
option = jqLite(select.find('option')[0]);
495+
expect(option.val()).toBe('');
496+
expect(option.text()).toBe('blank is so blank');
497+
});
498+
});
432499

433500
describe('on change', function() {
434501
it('should update model on change', function() {

0 commit comments

Comments
 (0)