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. Closes #4391.
  • Loading branch information
topherfangio authored and ThomasBurleson committed Sep 11, 2015
1 parent 316b4c8 commit 6681e82
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.

5 comments on commit 6681e82

@gpopovic
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chips work now but, but autocomplete width is too small :/ I'm getting trimmed text with "..." at the end (issue #4450)

Autocomplete alone doesn't work, i'm getting empty rows (let me check this one more time)

@topherfangio
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gpopovic Definitely let me know if this caused issues for the standard autocomplete and I will investigate.

@gpopovic
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@topherfangio one thing i notice is flicker ..

<md-item-template>
         <span md-highlight-text="vs" md-highlight-flags="i">{{::item.text()}}</span>
</md-item-template>

Since i can't use ng-bind because of md-highlight ...i often see on the first serach {{::item.text()}} for a really small time

@gpopovic
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@topherfangio i think i found a weird bug. When "item" in ng-repeat is not called item..search items are not displayed
http://codepen.io/anon/pen/gaajNM

@topherfangio
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gpopovic Can you possibly open a new issue with a Codepen so that I can see exactly what you're doing?

Please sign in to comment.