Skip to content
This repository has been archived by the owner on Feb 22, 2018. It is now read-only.

Commit

Permalink
fix(mustache): fix regression that fired an initial empty string
Browse files Browse the repository at this point in the history
Closes #734
  • Loading branch information
chirayuk committed Mar 20, 2014
1 parent 61c953d commit c71b8cf
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 17 deletions.
30 changes: 17 additions & 13 deletions lib/core_dom/directive.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
part of angular.core.dom;

/// Callback function used to notify of attribute changes.
typedef AttributeChanged(String newValue);
typedef void AttributeChanged(String newValue);

/// Callback function used to notify of observer changes.
typedef void ObserverChanged(bool hasListeners);
typedef void Mustache(bool hasObservers);

/**
* NodeAttrs is a facade for element attributes. The facade is responsible
Expand All @@ -16,13 +16,17 @@ class NodeAttrs {

Map<String, List<AttributeChanged>> _observers;

Map<String, List<ObserverChanged>> _observerListeners;
Map<String, Mustache> _mustacheObservers = {};
Set<String> _mustacheComputedAttrs = new Set<String>();

NodeAttrs(this.element);

operator [](String attributeName) => element.attributes[attributeName];

void operator []=(String attributeName, String value) {
if (_mustacheObservers.containsKey(attributeName)) {
_mustacheComputedAttrs.add(attributeName);
}
if (value == null) {
element.attributes.remove(attributeName);
} else {
Expand All @@ -43,11 +47,15 @@ class NodeAttrs {
_observers.putIfAbsent(attributeName, () => <AttributeChanged>[])
.add(notifyFn);

notifyFn(this[attributeName]);
bool hasMustache = _mustacheObservers.containsKey(attributeName);
bool hasMustacheAndIsComputed = _mustacheComputedAttrs.contains(attributeName);

if (!hasMustache || hasMustacheAndIsComputed) {
notifyFn(this[attributeName]);
}

if (_observerListeners != null &&
_observerListeners.containsKey(attributeName)) {
_observerListeners[attributeName].forEach((cb) => cb(true));
if (_mustacheObservers.containsKey(attributeName)) {
_mustacheObservers[attributeName](true);
}
}

Expand All @@ -60,12 +68,8 @@ class NodeAttrs {

Iterable<String> get keys => element.attributes.keys;

void listenObserverChanges(String attributeName, ObserverChanged fn) {
if (_observerListeners == null) {
_observerListeners = <String, List<ObserverChanged>>{};
}
_observerListeners.putIfAbsent(attributeName, () => <ObserverChanged>[])
.add(fn);
void listenObserverChanges(String attributeName, Mustache fn) {
_mustacheObservers[attributeName] = fn;
fn(false);
}
}
Expand Down
30 changes: 30 additions & 0 deletions test/core_dom/ng_mustache_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ main() {
TestBed _;
beforeEachModule((Module module) {
module.type(_HelloFilter);
module.type(_FooDirective);
});
beforeEach(inject((TestBed tb) => _ = tb));

Expand All @@ -23,6 +24,23 @@ main() {
expect(element.text()).toEqual('OK!');
}));

describe('observe/flush phase', () {
it('should first only when then value has settled', async((Logger log) {
_.compile('<div dir-foo="{{val}}"></div>');

_.rootScope.apply();
// _FooDirective should NOT have observed any changes.
expect(log).toEqual([]);
expect(_.rootElement.attributes['dir-foo']).toEqual('');

_.rootScope.apply(() {
_.rootScope.context['val'] = 'value';
});
// _FooDirective should have observed exactly one change.
expect(_.rootElement.attributes['dir-foo']).toEqual('value');
expect(log).toEqual(['value']);
}));
});

it('should replace {{}} in attribute', inject((Compiler $compile, Scope rootScope, Injector injector, DirectiveMap directives) {
var element = $('<div some-attr="{{name}}" other-attr="{{age}}"></div>');
Expand Down Expand Up @@ -117,3 +135,15 @@ class _HelloFilter {
}
}

@NgComponent(selector: '[dir-foo]')
class _FooDirective implements NgAttachAware {
NodeAttrs attrs;
Logger log;

_FooDirective(this.attrs, this.log);

@override
void attach() {
attrs.observe('dir-foo', (val) => log(val));
}
}
7 changes: 3 additions & 4 deletions test/directive/ng_src_boolean_spec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -93,18 +93,17 @@ main() {
TestBed _;
beforeEach((TestBed tb) => _ = tb);

it('should interpolate the expression and bind to src with raw same-domain value',
inject(() {
it('should interpolate the expression and bind to src with raw same-domain value', () {
_.compile('<div ng-src="{{id}}"></div>');

_.rootScope.apply();
expect(_.rootElement.attributes['src']).toEqual('');
expect(_.rootElement.attributes['src']).toEqual(null);

_.rootScope.apply(() {
_.rootScope.context['id'] = '/somewhere/here';
});
expect(_.rootElement.attributes['src']).toEqual('/somewhere/here');
}));
});


xit('should interpolate the expression and bind to src with a trusted value', ($sce) {
Expand Down

1 comment on commit c71b8cf

@jbdeboer
Copy link
Contributor

Choose a reason for hiding this comment

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

This commit broke the build.

Please sign in to comment.