From 5a9597168cb8b54e470b311c1dc87b22582c3581 Mon Sep 17 00:00:00 2001 From: "bigopon.777@gmail.com" Date: Fri, 24 May 2019 01:49:40 +1000 Subject: [PATCH 1/7] chore(tests): add failing test for 378 --- test/repeat.issue-378.spec.ts | 39 +++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 test/repeat.issue-378.spec.ts diff --git a/test/repeat.issue-378.spec.ts b/test/repeat.issue-378.spec.ts new file mode 100644 index 0000000..b332109 --- /dev/null +++ b/test/repeat.issue-378.spec.ts @@ -0,0 +1,39 @@ +import './setup'; +import { StageComponent } from 'aurelia-testing'; +import { bootstrap } from 'aurelia-bootstrapper'; + +// https://github.com/aurelia/templating-resources/issues/378 +fdescribe('repeat.issue-378.spec.ts', () => { + it('with matcher', async () => { + const component = StageComponent + .withResources() + .inView(``) + .boundTo(new class { + products = [ + { id: 0, name: 'Motherboard' }, + { id: 1, name: 'CPU' }, + { id: 2, name: 'Memory' } + ]; + + productMatcher = (a, b) => { + console.log('matcher'); + return a.id === b.id; + } + + selectedProduct = { id: 1, name: 'CPU' }; + }); + + await component.create(bootstrap); + const radios = document.querySelectorAll('input[type=radio]') as ArrayLike; + expect(radios.length).toBe(3); + expect(radios[1].checked).toBe(true); + }); +}); From a5796443016d2c87269dd05801c057fb45e5dc44 Mon Sep 17 00:00:00 2001 From: "bigopon.777@gmail.com" Date: Fri, 24 May 2019 02:25:50 +1000 Subject: [PATCH 2/7] fix(repeat): properly find matcher binding --- src/aurelia-templating-resources.ts | 1 + src/interfaces.ts | 17 +++++++++++ src/repeat.ts | 42 +++++++++++++++++++++++---- test/repeat.issue-378.spec.ts | 44 ++++++++++++++++++----------- test/test-utilities.ts | 7 +++++ 5 files changed, 88 insertions(+), 23 deletions(-) create mode 100644 src/interfaces.ts create mode 100644 test/test-utilities.ts diff --git a/src/aurelia-templating-resources.ts b/src/aurelia-templating-resources.ts index ac11261..4527d19 100644 --- a/src/aurelia-templating-resources.ts +++ b/src/aurelia-templating-resources.ts @@ -37,6 +37,7 @@ import { } from './repeat-utilities'; import {viewsRequireLifecycle} from './analyze-view-factory'; import {injectAureliaHideStyleAtHead} from './aurelia-hide-style'; +import './interfaces'; function configure(config: any) { injectAureliaHideStyleAtHead(); diff --git a/src/interfaces.ts b/src/interfaces.ts new file mode 100644 index 0000000..23377ab --- /dev/null +++ b/src/interfaces.ts @@ -0,0 +1,17 @@ +import { BindingExpression } from 'aurelia-binding'; +import { TargetInstruction } from 'aurelia-templating'; + +/**@internal */ +declare module 'aurelia-templating' { + interface ViewFactory { + instructions: Record; + template: DocumentFragment; + } +} + +/**@internal */ +declare module 'aurelia-binding' { + interface BindingExpression { + targetProperty: string; + } +} diff --git a/src/repeat.ts b/src/repeat.ts index bae8992..97c5423 100644 --- a/src/repeat.ts +++ b/src/repeat.ts @@ -1,6 +1,6 @@ /*eslint no-loop-func:0, no-unused-vars:0*/ import {inject} from 'aurelia-dependency-injection'; -import {ObserverLocator} from 'aurelia-binding'; +import {ObserverLocator, BindingExpression} from 'aurelia-binding'; import { BoundViewFactory, TargetInstruction, @@ -9,7 +9,8 @@ import { customAttribute, bindable, templateController, - View + View, + ViewFactory } from 'aurelia-templating'; import {RepeatStrategyLocator} from './repeat-strategy-locator'; import { @@ -259,14 +260,38 @@ export class Repeat extends AbstractRepeater { } /** + * Capture and remove matcher binding is a way to cache matcher binding + reduce redundant work + * caused by multiple unnecessary matcher bindings * @internal */ _captureAndRemoveMatcherBinding() { - if (this.viewFactory.viewFactory) { - const instructions = this.viewFactory.viewFactory.instructions; + const viewFactory: ViewFactory = this.viewFactory.viewFactory; + if (viewFactory) { + const template = viewFactory.template; + const instructions = viewFactory.instructions; const instructionIds = Object.keys(instructions); + // if the template has more than 1 immediate child element + // it's a repeat put on a