Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

Commit

Permalink
fix(mdAutocomplete): Compile autocomplete template against proper scope.
Browse files Browse the repository at this point in the history
After the performance modifications to make autocomplete use the
virtual repeat directive, the autocomplete no longer compiled the
contents of the dropdown against the proper parent scope

This PR fixes it by manually compiling against the proper parent scope
and copying over the necessary `item` and `$index` properties.

Fixes #4390. Fixes #4495.
  • Loading branch information
topherfangio committed Sep 9, 2015
1 parent d7ffe17 commit bcf67a5
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 24 deletions.
42 changes: 42 additions & 0 deletions src/components/autocomplete/autocomplete.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,48 @@ describe('<md-autocomplete>', function () {

element.remove();
}));

it('should compile the template against the parent scope', inject(function ($timeout) {
var scope = createScope(null, { bang: 'boom' });
var template = '\
<md-autocomplete\
md-selected-item="selectedItem"\
md-search-text="searchText"\
md-items="item in match(searchText)"\
md-item-text="item.display"\
placeholder="placeholder">\
<md-item-template>\
<span class="find-parent-scope">{{bang}}</span>\
<span class="find-index">{{$index}}</span>\
<span class="find-item">{{item.display}}</span>\
</md-item-template>\
</md-autocomplete>';
var element = compile(template, scope);
var ctrl = element.controller('mdAutocomplete');
var ul = element.find('ul');

expect(scope.bang).toBe('boom');

element.scope().searchText = 'fo';

// Run our initial flush
$timeout.flush();
waitForVirtualRepeat(element);

// Wait for the next tick when the values will be updated
$timeout.flush();

var li = ul.find('li')[0];

// Expect it to be compiled against the parent scope and have our variables copied
expect(li.querySelector('.find-parent-scope').innerHTML).toBe('boom');
expect(li.querySelector('.find-index').innerHTML).toBe('0');
expect(li.querySelector('.find-item').innerHTML).toBe('foo');

$timeout.flush();

element.remove();
}));
});

describe('xss prevention', function () {
Expand Down
2 changes: 1 addition & 1 deletion src/components/autocomplete/js/autocompleteDirective.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ function MdAutocomplete () {
var templateTag = element.find('md-item-template').detach(),
html = templateTag.length ? templateTag.html() : element.html();
if (!templateTag.length) element.empty();
return html;
return '<md-autocomplete-parent-scope md-autocomplete-replace>' + html + '</md-autocomplete-parent-scope>';
}

function getNoItemsTemplate() {
Expand Down
34 changes: 34 additions & 0 deletions src/components/autocomplete/js/autocompleteParentScopeDirective.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
angular
.module('material.components.autocomplete')
.directive('mdAutocompleteParentScope', MdAutocompleteItemScopeDirective);

function MdAutocompleteItemScopeDirective($compile, $mdUtil) {
return {
restrict: 'AE',
link: postLink,
terminal: true
};

function postLink(scope, element, attr) {
var newScope = scope.$mdAutocompleteCtrl.parent.$new();
var relevantVariables = ['item', '$index'];

// Watch for changes to our scope's variables and copy them to the new scope
angular.forEach(relevantVariables, function(variable){
scope.$watch(variable, function(value) {
$mdUtil.nextTick(function() {
newScope[variable] = value;
});
});
});

// Recompile the contents with the new/modified scope
$compile(element.contents())(newScope);

// Replace it if required
if (attr.hasOwnProperty('mdAutocompleteReplace')) {
element.after(element.contents());
element.remove();
}
}
}
23 changes: 0 additions & 23 deletions src/components/autocomplete/js/parentScope.js

This file was deleted.

0 comments on commit bcf67a5

Please sign in to comment.