From a2183ddb7a8efd320d5e5c38a029a5960caa1cfc Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Thu, 1 Aug 2019 09:01:58 +0300 Subject: [PATCH] fix(ivy): directive matching not working in some cases when preceded by styling attributes (#31942) Fixes Ivy's directive matching not capturing attribute selectors when there is one class binding, one style binding and a regular binding that precede the attribute that would match the directive. The issue appears to come from the fact that we weren't skipping over style bindings correctly which was throwing the loop off not to go into `bindingsMode` and to skip some of the bindings when matching. PR Close #31942 --- .../core/src/render3/node_selector_matcher.ts | 3 +- .../core/test/acceptance/directive_spec.ts | 33 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/packages/core/src/render3/node_selector_matcher.ts b/packages/core/src/render3/node_selector_matcher.ts index 594eb9c9b6..73ada1af36 100644 --- a/packages/core/src/render3/node_selector_matcher.ts +++ b/packages/core/src/render3/node_selector_matcher.ts @@ -198,7 +198,8 @@ function findAttrIndexInNode( } else if ( maybeAttrName === AttributeMarker.Bindings || maybeAttrName === AttributeMarker.I18n) { bindingsMode = true; - } else if (maybeAttrName === AttributeMarker.Classes) { + } else if ( + maybeAttrName === AttributeMarker.Classes || maybeAttrName === AttributeMarker.Styles) { let value = attrs[++i]; // We should skip classes here because we have a separate mechanism for // matching classes in projection mode. diff --git a/packages/core/test/acceptance/directive_spec.ts b/packages/core/test/acceptance/directive_spec.ts index ee411dcd4c..31905992e8 100644 --- a/packages/core/test/acceptance/directive_spec.ts +++ b/packages/core/test/acceptance/directive_spec.ts @@ -226,6 +226,39 @@ describe('directives', () => { expect(calls).toEqual(['MyDir.ngOnInit']); }); + it('should match directives when the node has "class", "style" and a binding', () => { + const logs: string[] = []; + + @Directive({selector: '[test]'}) + class MyDir { + constructor() { logs.push('MyDir.contructor'); } + + @Input('test') + myInput = ''; + + @Input('disabled') + myInput2 = ''; + } + + @Component({ + // Note that below we're checking the case where the `test` attribute is after + // one `class`, one `attribute` and one other binding. + template: ` +
+ ` + }) + class MyComp { + test = ''; + } + + TestBed.configureTestingModule({declarations: [MyComp, MyDir]}); + + const fixture = TestBed.createComponent(MyComp); + fixture.detectChanges(); + + expect(logs).toEqual(['MyDir.contructor']); + }); + }); describe('outputs', () => {