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

fix(autocomlete): Gets rid of uncompiled content flicker. #5637

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions src/components/autocomplete/autocomplete.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,54 @@ describe('<md-autocomplete>', function() {
element.remove();
}));

it('should ensure the parent scope digests along with the current scope', inject(function($timeout, $material) {
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');

$material.flushOutstandingAnimations();

// Focus the input
ctrl.focus();

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];
var parentScope = angular.element(li.querySelector('.find-parent-scope')).scope();

// When the autocomplete item's scope digests, ensure that the parent
// scope does too.
parentScope.bang = 'big';
scope.$digest();

expect(li.querySelector('.find-parent-scope').innerHTML).toBe('big');

// Make sure we wrap up anything and remove the element
$timeout.flush();
element.remove();
}));

it('is hidden when no matches are found without an md-not-found template', inject(function($timeout, $material) {
var scope = createScope();
var template =
Expand Down
96 changes: 63 additions & 33 deletions src/components/autocomplete/js/autocompleteParentScopeDirective.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,71 @@ angular
function MdAutocompleteItemScopeDirective($compile, $mdUtil) {
return {
restrict: 'AE',
link: postLink,
terminal: true
compile: compile,
terminal: true,
transclude: 'element'
};

function postLink(scope, element, attr) {
var ctrl = scope.$mdAutocompleteCtrl;
var newScope = ctrl.parent.$new();
var itemName = ctrl.itemName;

// Watch for changes to our scope's variables and copy them to the new scope
watchVariable('$index', '$index');
watchVariable('item', itemName);

// 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();
}

/**
* Creates a watcher for variables that are copied from the parent scope
* @param variable
* @param alias
*/
function watchVariable(variable, alias) {
newScope[alias] = scope[variable];

scope.$watch(variable, function(value) {
$mdUtil.nextTick(function() {
newScope[alias] = value;
});
function compile(tElement, tAttr, transclude) {
return function postLink(scope, element, attr) {
var ctrl = scope.$mdAutocompleteCtrl;
var newScope = ctrl.parent.$new();
var itemName = ctrl.itemName;

// Watch for changes to our scope's variables and copy them to the new scope
watchVariable('$index', '$index');
watchVariable('item', itemName);

// Ensure that $digest calls on our scope trigger $digest on newScope.
connectScopes();

// Link the element against newScope.
transclude(newScope, function(clone) {
element.after(clone);
});
}

/**
* Creates a watcher for variables that are copied from the parent scope
* @param variable
* @param alias
*/
function watchVariable(variable, alias) {
newScope[alias] = scope[variable];

scope.$watch(variable, function(value) {
$mdUtil.nextTick(function() {
newScope[alias] = value;
});
});
}

/**
* Creates watchers on scope and newScope that ensure that for any
* $digest of scope, newScope is also $digested.
*/
function connectScopes() {
var scopeDigesting = false;
var newScopeDigesting = false;

scope.$watch(function() {
if (newScopeDigesting || scopeDigesting) {
return;
}

scopeDigesting = true;
scope.$$postDigest(function() {
if (!newScopeDigesting) {
newScope.$digest();
}

scopeDigesting = newScopeDigesting = false;
});
});

newScope.$watch(function() {
newScopeDigesting = true;
});
}
};
}
}
2 changes: 1 addition & 1 deletion src/components/autocomplete/js/highlightController.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function MdHighlightCtrl ($scope, $element, $attrs) {

$element.html(text.replace(regex, '<span class="highlight">$&</span>'));
}, true);
$element.on('$destroy', function () { watcher(); });
$element.on('$destroy', watcher);
}

function sanitize (term) {
Expand Down