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

Commit

Permalink
fix(autocomlete): Gets rid of uncompiled content flicker. Works aroun…
Browse files Browse the repository at this point in the history
…d issues cased by the scope discontinuity in autocompleteParentScopeDirective.

add a unit test

Closes #5637
  • Loading branch information
kseamon authored and jelbourn committed Dec 8, 2015
1 parent 36efd3f commit 88ba1fd
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 34 deletions.
48 changes: 48 additions & 0 deletions src/components/autocomplete/autocomplete.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,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

0 comments on commit 88ba1fd

Please sign in to comment.