diff --git a/.changeset/witty-monkeys-dance.md b/.changeset/witty-monkeys-dance.md new file mode 100644 index 0000000000..3e362ddf7e --- /dev/null +++ b/.changeset/witty-monkeys-dance.md @@ -0,0 +1,5 @@ +--- +'@builder.io/mitosis': patch +--- + +Feat: `trackBy` for angular (can be used when the child used inside has a `key` attribute in mitosis) diff --git a/packages/core/src/__tests__/__snapshots__/angular.import.test.ts.snap b/packages/core/src/__tests__/__snapshots__/angular.import.test.ts.snap index 05cc4b4398..af632afd01 100644 --- a/packages/core/src/__tests__/__snapshots__/angular.import.test.ts.snap +++ b/packages/core/src/__tests__/__snapshots__/angular.import.test.ts.snap @@ -1120,7 +1120,7 @@ import { > - +
@@ -2101,6 +2106,9 @@ export default class SmileReviews { snakeCaseValue() { return snakeCase(\\"testThis\\"); } + trackByReview0(index, review) { + return review.id; + } ngOnInit() { if (typeof window !== \\"undefined\\") { @@ -4104,7 +4112,9 @@ import RenderRepeatedBlock from \\"./render-repeated-block.lite\\"; > - + - +
{{item}}
@@ -4661,6 +4682,10 @@ import { Component, Input } from \\"@angular/core\\"; export default class NestedShow { @Input() conditionA; @Input() items; + + trackByItem0(idx, item) { + return idx; + } } @NgModule({ @@ -5050,6 +5075,51 @@ export class SvgComponentModule {} " `; +exports[`Angular with Preserve Imports and File Extensions > jsx > Javascript Test > twoForsTrackBy 1`] = ` +"import { NgModule } from \\"@angular/core\\"; +import { CommonModule } from \\"@angular/common\\"; + +import { Component } from \\"@angular/core\\"; + +@Component({ + selector: \\"my-component, MyComponent\\", + template: \` +
+ +
{{item}}
+
+ +
{{item}}
+
+
+ \`, + styles: [ + \` + :host { + display: contents; + } + \`, + ], +}) +export default class MyComponent { + items = [1, 2, 3]; + trackByItem0(_, item) { + return item; + } + trackByItem1(_, item) { + return item; + } +} + +@NgModule({ + declarations: [MyComponent], + imports: [CommonModule], + exports: [MyComponent], +}) +export class MyComponentModule {} +" +`; + exports[`Angular with Preserve Imports and File Extensions > jsx > Javascript Test > typeDependency 1`] = ` "import { NgModule } from \\"@angular/core\\"; import { CommonModule } from \\"@angular/common\\"; @@ -6524,7 +6594,7 @@ import { > - +
@@ -7608,6 +7683,9 @@ export default class SmileReviews { snakeCaseValue() { return snakeCase(\\"testThis\\"); } + trackByReview0(index, review) { + return review.id; + } ngOnInit() { if (typeof window !== \\"undefined\\") { @@ -9783,7 +9861,9 @@ import type { RepeatData } from \\"./types.js\\"; > - + - +
{{item}}
@@ -10369,6 +10460,10 @@ interface Props { export default class NestedShow { @Input() conditionA!: Props[\\"conditionA\\"]; @Input() items!: Props[\\"items\\"]; + + trackByItem0(idx, item) { + return idx; + } } @NgModule({ @@ -10775,6 +10870,51 @@ export class SvgComponentModule {} " `; +exports[`Angular with Preserve Imports and File Extensions > jsx > Typescript Test > twoForsTrackBy 1`] = ` +"import { NgModule } from \\"@angular/core\\"; +import { CommonModule } from \\"@angular/common\\"; + +import { Component } from \\"@angular/core\\"; + +@Component({ + selector: \\"my-component, MyComponent\\", + template: \` +
+ +
{{item}}
+
+ +
{{item}}
+
+
+ \`, + styles: [ + \` + :host { + display: contents; + } + \`, + ], +}) +export default class MyComponent { + items = [1, 2, 3]; + trackByItem0(_, item) { + return item; + } + trackByItem1(_, item) { + return item; + } +} + +@NgModule({ + declarations: [MyComponent], + imports: [CommonModule], + exports: [MyComponent], +}) +export class MyComponentModule {} +" +`; + exports[`Angular with Preserve Imports and File Extensions > jsx > Typescript Test > typeDependency 1`] = ` "import { NgModule } from \\"@angular/core\\"; import { CommonModule } from \\"@angular/common\\"; diff --git a/packages/core/src/__tests__/__snapshots__/angular.mapper.test.ts.snap b/packages/core/src/__tests__/__snapshots__/angular.mapper.test.ts.snap index 43a3d72d15..cf7bc32ccf 100644 --- a/packages/core/src/__tests__/__snapshots__/angular.mapper.test.ts.snap +++ b/packages/core/src/__tests__/__snapshots__/angular.mapper.test.ts.snap @@ -1140,7 +1140,7 @@ import { > - +
@@ -2135,6 +2140,9 @@ export default class SmileReviews { snakeCaseValue() { return snakeCase(\\"testThis\\"); } + trackByReview0(index, review) { + return review.id; + } ngOnInit() { if (typeof window !== \\"undefined\\") { @@ -4185,7 +4193,9 @@ import RenderRepeatedBlockModule from \\"./render-repeated-block.lite/angular\\" > - + - +
{{item}}
@@ -4749,6 +4770,10 @@ import { Component, Input } from \\"@angular/core\\"; export default class NestedShow { @Input() conditionA; @Input() items; + + trackByItem0(idx, item) { + return idx; + } } @NgModule({ @@ -5149,6 +5174,52 @@ export class SvgComponentModule {} " `; +exports[`Angular with Import Mapper Tests > jsx > Javascript Test > twoForsTrackBy 1`] = ` +"import { NgModule } from \\"@angular/core\\"; +import { CommonModule } from \\"@angular/common\\"; + +import { Component } from \\"@angular/core\\"; + +@Component({ + selector: \\"my-component, MyComponent\\", + template: \` +
+ +
{{item}}
+
+ +
{{item}}
+
+
+ \`, + styles: [ + \` + :host { + display: contents; + } + \`, + ], +}) +export default class MyComponent { + items = [1, 2, 3]; + trackByItem0(_, item) { + return item; + } + trackByItem1(_, item) { + return item; + } +} + +@NgModule({ + declarations: [MyComponent], + imports: [CommonModule], + exports: [MyComponent], + bootstrap: [SomeOtherComponent], +}) +export class MyComponentModule {} +" +`; + exports[`Angular with Import Mapper Tests > jsx > Javascript Test > typeDependency 1`] = ` "import { NgModule } from \\"@angular/core\\"; import { CommonModule } from \\"@angular/common\\"; @@ -6650,7 +6721,7 @@ import { > - +
@@ -7748,6 +7824,9 @@ export default class SmileReviews { snakeCaseValue() { return snakeCase(\\"testThis\\"); } + trackByReview0(index, review) { + return review.id; + } ngOnInit() { if (typeof window !== \\"undefined\\") { @@ -9972,7 +10051,9 @@ import { RepeatData } from \\"./types.js\\"; > - + - +
{{item}}
@@ -10565,6 +10657,10 @@ interface Props { export default class NestedShow { @Input() conditionA!: Props[\\"conditionA\\"]; @Input() items!: Props[\\"items\\"]; + + trackByItem0(idx, item) { + return idx; + } } @NgModule({ @@ -10982,6 +11078,52 @@ export class SvgComponentModule {} " `; +exports[`Angular with Import Mapper Tests > jsx > Typescript Test > twoForsTrackBy 1`] = ` +"import { NgModule } from \\"@angular/core\\"; +import { CommonModule } from \\"@angular/common\\"; + +import { Component } from \\"@angular/core\\"; + +@Component({ + selector: \\"my-component, MyComponent\\", + template: \` +
+ +
{{item}}
+
+ +
{{item}}
+
+
+ \`, + styles: [ + \` + :host { + display: contents; + } + \`, + ], +}) +export default class MyComponent { + items = [1, 2, 3]; + trackByItem0(_, item) { + return item; + } + trackByItem1(_, item) { + return item; + } +} + +@NgModule({ + declarations: [MyComponent], + imports: [CommonModule], + exports: [MyComponent], + bootstrap: [SomeOtherComponent], +}) +export class MyComponentModule {} +" +`; + exports[`Angular with Import Mapper Tests > jsx > Typescript Test > typeDependency 1`] = ` "import { NgModule } from \\"@angular/core\\"; import { CommonModule } from \\"@angular/common\\"; diff --git a/packages/core/src/__tests__/__snapshots__/angular.state.test.ts.snap b/packages/core/src/__tests__/__snapshots__/angular.state.test.ts.snap index 1b02771a79..ef3ea6d7fe 100644 --- a/packages/core/src/__tests__/__snapshots__/angular.state.test.ts.snap +++ b/packages/core/src/__tests__/__snapshots__/angular.state.test.ts.snap @@ -1161,7 +1161,7 @@ import { > - +
@@ -2191,6 +2196,9 @@ export default class SmileReviews { event.preventDefault(); this.showReviewPrompt = false; }; + trackByReview0(index, review) { + return review.id; + } ngOnInit() { if (typeof window !== \\"undefined\\") { @@ -4282,7 +4290,9 @@ import { isEmptyHtmlElement } from \\"./render-block.helpers.js\\"; > - + - +
{{item}}
@@ -4860,6 +4881,10 @@ import { Component, Input } from \\"@angular/core\\"; export default class NestedShow { @Input() conditionA; @Input() items; + + trackByItem0(idx, item) { + return idx; + } } @NgModule({ @@ -5252,6 +5277,51 @@ export class SvgComponentModule {} " `; +exports[`Angular with manually creating and handling class properties as bindings (more stable) > jsx > Javascript Test > twoForsTrackBy 1`] = ` +"import { NgModule } from \\"@angular/core\\"; +import { CommonModule } from \\"@angular/common\\"; + +import { Component } from \\"@angular/core\\"; + +@Component({ + selector: \\"my-component, MyComponent\\", + template: \` +
+ +
{{item}}
+
+ +
{{item}}
+
+
+ \`, + styles: [ + \` + :host { + display: contents; + } + \`, + ], +}) +export default class MyComponent { + items = [1, 2, 3]; + trackByItem0(_, item) { + return item; + } + trackByItem1(_, item) { + return item; + } +} + +@NgModule({ + declarations: [MyComponent], + imports: [CommonModule], + exports: [MyComponent], +}) +export class MyComponentModule {} +" +`; + exports[`Angular with manually creating and handling class properties as bindings (more stable) > jsx > Javascript Test > typeDependency 1`] = ` "import { NgModule } from \\"@angular/core\\"; import { CommonModule } from \\"@angular/common\\"; @@ -6767,7 +6837,7 @@ import { > - +
@@ -7900,6 +7975,9 @@ export default class SmileReviews { event.preventDefault(); this.showReviewPrompt = false; }; + trackByReview0(index, review) { + return review.id; + } ngOnInit() { if (typeof window !== \\"undefined\\") { @@ -10162,7 +10240,9 @@ import type { RepeatData } from \\"./types.js\\"; > - + - +
{{item}}
@@ -10769,6 +10860,10 @@ interface Props { export default class NestedShow { @Input() conditionA!: Props[\\"conditionA\\"]; @Input() items!: Props[\\"items\\"]; + + trackByItem0(idx, item) { + return idx; + } } @NgModule({ @@ -11178,6 +11273,51 @@ export class SvgComponentModule {} " `; +exports[`Angular with manually creating and handling class properties as bindings (more stable) > jsx > Typescript Test > twoForsTrackBy 1`] = ` +"import { NgModule } from \\"@angular/core\\"; +import { CommonModule } from \\"@angular/common\\"; + +import { Component } from \\"@angular/core\\"; + +@Component({ + selector: \\"my-component, MyComponent\\", + template: \` +
+ +
{{item}}
+
+ +
{{item}}
+
+
+ \`, + styles: [ + \` + :host { + display: contents; + } + \`, + ], +}) +export default class MyComponent { + items = [1, 2, 3]; + trackByItem0(_, item) { + return item; + } + trackByItem1(_, item) { + return item; + } +} + +@NgModule({ + declarations: [MyComponent], + imports: [CommonModule], + exports: [MyComponent], +}) +export class MyComponentModule {} +" +`; + exports[`Angular with manually creating and handling class properties as bindings (more stable) > jsx > Typescript Test > typeDependency 1`] = ` "import { NgModule } from \\"@angular/core\\"; import { CommonModule } from \\"@angular/common\\"; diff --git a/packages/core/src/__tests__/__snapshots__/angular.styles.test.ts.snap b/packages/core/src/__tests__/__snapshots__/angular.styles.test.ts.snap index 0595d3d965..ecb90d02bc 100644 --- a/packages/core/src/__tests__/__snapshots__/angular.styles.test.ts.snap +++ b/packages/core/src/__tests__/__snapshots__/angular.styles.test.ts.snap @@ -996,7 +996,7 @@ import { > - +
@@ -1884,6 +1889,9 @@ export default class SmileReviews { snakeCaseValue() { return snakeCase(\\"testThis\\"); } + trackByReview0(index, review) { + return review.id; + } ngOnInit() { if (typeof window !== \\"undefined\\") { @@ -3587,7 +3595,9 @@ import { isEmptyHtmlElement } from \\"./render-block.helpers.js\\"; > - + - +
{{item}}
@@ -4090,6 +4111,10 @@ import { Component, Input } from \\"@angular/core\\"; export default class NestedShow { @Input() conditionA; @Input() items; + + trackByItem0(idx, item) { + return idx; + } } @NgModule({ @@ -4419,6 +4444,44 @@ export class SvgComponentModule {} " `; +exports[`Angular with visuallyIgnoreHostElement = false > jsx > Javascript Test > twoForsTrackBy 1`] = ` +"import { NgModule } from \\"@angular/core\\"; +import { CommonModule } from \\"@angular/common\\"; + +import { Component } from \\"@angular/core\\"; + +@Component({ + selector: \\"my-component, MyComponent\\", + template: \` +
+ +
{{item}}
+
+ +
{{item}}
+
+
+ \`, +}) +export default class MyComponent { + items = [1, 2, 3]; + trackByItem0(_, item) { + return item; + } + trackByItem1(_, item) { + return item; + } +} + +@NgModule({ + declarations: [MyComponent], + imports: [CommonModule], + exports: [MyComponent], +}) +export class MyComponentModule {} +" +`; + exports[`Angular with visuallyIgnoreHostElement = false > jsx > Javascript Test > typeDependency 1`] = ` "import { NgModule } from \\"@angular/core\\"; import { CommonModule } from \\"@angular/common\\"; @@ -5732,7 +5795,7 @@ import { > - +
@@ -6723,6 +6791,9 @@ export default class SmileReviews { snakeCaseValue() { return snakeCase(\\"testThis\\"); } + trackByReview0(index, review) { + return review.id; + } ngOnInit() { if (typeof window !== \\"undefined\\") { @@ -8597,7 +8668,9 @@ import type { RepeatData } from \\"./types.js\\"; > - + - +
{{item}}
@@ -9129,6 +9213,10 @@ interface Props { export default class NestedShow { @Input() conditionA!: Props[\\"conditionA\\"]; @Input() items!: Props[\\"items\\"]; + + trackByItem0(idx, item) { + return idx; + } } @NgModule({ @@ -9475,6 +9563,44 @@ export class SvgComponentModule {} " `; +exports[`Angular with visuallyIgnoreHostElement = false > jsx > Typescript Test > twoForsTrackBy 1`] = ` +"import { NgModule } from \\"@angular/core\\"; +import { CommonModule } from \\"@angular/common\\"; + +import { Component } from \\"@angular/core\\"; + +@Component({ + selector: \\"my-component, MyComponent\\", + template: \` +
+ +
{{item}}
+
+ +
{{item}}
+
+
+ \`, +}) +export default class MyComponent { + items = [1, 2, 3]; + trackByItem0(_, item) { + return item; + } + trackByItem1(_, item) { + return item; + } +} + +@NgModule({ + declarations: [MyComponent], + imports: [CommonModule], + exports: [MyComponent], +}) +export class MyComponentModule {} +" +`; + exports[`Angular with visuallyIgnoreHostElement = false > jsx > Typescript Test > typeDependency 1`] = ` "import { NgModule } from \\"@angular/core\\"; import { CommonModule } from \\"@angular/common\\"; diff --git a/packages/core/src/__tests__/__snapshots__/angular.test.ts.snap b/packages/core/src/__tests__/__snapshots__/angular.test.ts.snap index 65d272bc9a..f7fd00ca9b 100644 --- a/packages/core/src/__tests__/__snapshots__/angular.test.ts.snap +++ b/packages/core/src/__tests__/__snapshots__/angular.test.ts.snap @@ -2069,7 +2069,7 @@ import { > - +
@@ -3874,6 +3882,9 @@ export default class SmileReviews { snakeCaseValue() { return snakeCase(\\"testThis\\"); } + trackByReview0(index, review) { + return review.id; + } ngOnInit() { if (typeof window !== \\"undefined\\") { @@ -3927,7 +3938,9 @@ import { kebabCase, snakeCase } from \\"lodash\\"; Submit - +
@@ -3985,6 +3998,9 @@ export default class SmileReviews { snakeCaseValue() { return snakeCase(\\"testThis\\"); } + trackByReview0(index, review) { + return review.id; + } ngOnInit() { if (typeof window !== \\"undefined\\") { @@ -7588,7 +7604,9 @@ import { isEmptyHtmlElement } from \\"./render-block.helpers.js\\"; > - + - + - +
{{item}}
@@ -8660,6 +8700,10 @@ import { Component, Input } from \\"@angular/core\\"; export default class NestedShow { @Input() conditionA; @Input() items; + + trackByItem0(idx, item) { + return idx; + } } @NgModule({ @@ -8679,7 +8723,9 @@ import { CommonModule } from \\"@angular/common\\"; selector: \\"nested-show, NestedShow\\", template: \` - +
{{item}}
@@ -8700,6 +8746,10 @@ import { CommonModule } from \\"@angular/common\\"; export default class NestedShow { @Input() conditionA; @Input() items; + + trackByItem0(idx, item) { + return idx; + } } " `; @@ -9388,6 +9438,89 @@ export default class SvgComponent {} " `; +exports[`Angular > jsx > Javascript Test > twoForsTrackBy 1`] = ` +"import { NgModule } from \\"@angular/core\\"; +import { CommonModule } from \\"@angular/common\\"; + +import { Component } from \\"@angular/core\\"; + +@Component({ + selector: \\"my-component, MyComponent\\", + template: \` +
+ +
{{item}}
+
+ +
{{item}}
+
+
+ \`, + styles: [ + \` + :host { + display: contents; + } + \`, + ], +}) +export default class MyComponent { + items = [1, 2, 3]; + trackByItem0(_, item) { + return item; + } + trackByItem1(_, item) { + return item; + } +} + +@NgModule({ + declarations: [MyComponent], + imports: [CommonModule], + exports: [MyComponent], +}) +export class MyComponentModule {} +" +`; + +exports[`Angular > jsx > Javascript Test > twoForsTrackBy 2`] = ` +"import { Component } from \\"@angular/core\\"; +import { CommonModule } from \\"@angular/common\\"; + +@Component({ + selector: \\"my-component, MyComponent\\", + template: \` +
+ +
{{item}}
+
+ +
{{item}}
+
+
+ \`, + styles: [ + \` + :host { + display: contents; + } + \`, + ], + standalone: true, + imports: [CommonModule], +}) +export default class MyComponent { + items = [1, 2, 3]; + trackByItem0(_, item) { + return item; + } + trackByItem1(_, item) { + return item; + } +} +" +`; + exports[`Angular > jsx > Javascript Test > typeDependency 1`] = ` "import { NgModule } from \\"@angular/core\\"; import { CommonModule } from \\"@angular/common\\"; @@ -12092,7 +12225,7 @@ import { > - +
@@ -14122,6 +14263,9 @@ export default class SmileReviews { snakeCaseValue() { return snakeCase(\\"testThis\\"); } + trackByReview0(index, review) { + return review.id; + } ngOnInit() { if (typeof window !== \\"undefined\\") { @@ -14180,7 +14324,9 @@ import { kebabCase, snakeCase } from \\"lodash\\"; Submit - +
@@ -14238,6 +14384,9 @@ export default class SmileReviews { snakeCaseValue() { return snakeCase(\\"testThis\\"); } + trackByReview0(index, review) { + return review.id; + } ngOnInit() { if (typeof window !== \\"undefined\\") { @@ -18171,7 +18320,9 @@ import type { RepeatData } from \\"./types.js\\"; > - + - + - +
{{item}}
@@ -19309,6 +19482,10 @@ interface Props { export default class NestedShow { @Input() conditionA!: Props[\\"conditionA\\"]; @Input() items!: Props[\\"items\\"]; + + trackByItem0(idx, item) { + return idx; + } } @NgModule({ @@ -19333,7 +19510,9 @@ interface Props { selector: \\"nested-show, NestedShow\\", template: \` - +
{{item}}
@@ -19354,6 +19533,10 @@ interface Props { export default class NestedShow { @Input() conditionA!: Props[\\"conditionA\\"]; @Input() items!: Props[\\"items\\"]; + + trackByItem0(idx, item) { + return idx; + } } " `; @@ -20076,6 +20259,89 @@ export default class SvgComponent {} " `; +exports[`Angular > jsx > Typescript Test > twoForsTrackBy 1`] = ` +"import { NgModule } from \\"@angular/core\\"; +import { CommonModule } from \\"@angular/common\\"; + +import { Component } from \\"@angular/core\\"; + +@Component({ + selector: \\"my-component, MyComponent\\", + template: \` +
+ +
{{item}}
+
+ +
{{item}}
+
+
+ \`, + styles: [ + \` + :host { + display: contents; + } + \`, + ], +}) +export default class MyComponent { + items = [1, 2, 3]; + trackByItem0(_, item) { + return item; + } + trackByItem1(_, item) { + return item; + } +} + +@NgModule({ + declarations: [MyComponent], + imports: [CommonModule], + exports: [MyComponent], +}) +export class MyComponentModule {} +" +`; + +exports[`Angular > jsx > Typescript Test > twoForsTrackBy 2`] = ` +"import { Component } from \\"@angular/core\\"; +import { CommonModule } from \\"@angular/common\\"; + +@Component({ + selector: \\"my-component, MyComponent\\", + template: \` +
+ +
{{item}}
+
+ +
{{item}}
+
+
+ \`, + styles: [ + \` + :host { + display: contents; + } + \`, + ], + standalone: true, + imports: [CommonModule], +}) +export default class MyComponent { + items = [1, 2, 3]; + trackByItem0(_, item) { + return item; + } + trackByItem1(_, item) { + return item; + } +} +" +`; + exports[`Angular > jsx > Typescript Test > typeDependency 1`] = ` "import { NgModule } from \\"@angular/core\\"; import { CommonModule } from \\"@angular/common\\"; diff --git a/packages/core/src/__tests__/data/angular/two-fors.raw.tsx b/packages/core/src/__tests__/data/angular/two-fors.raw.tsx new file mode 100644 index 0000000000..672e2ed0bb --- /dev/null +++ b/packages/core/src/__tests__/data/angular/two-fors.raw.tsx @@ -0,0 +1,12 @@ +import { For, useState } from '@builder.io/mitosis'; + +export default function MyComponent() { + const [items] = useState([1, 2, 3]); + + return ( +
+ {(item) =>
{item}
}
+ {(item) =>
{item}
}
+
+ ); +} diff --git a/packages/core/src/__tests__/test-generator.ts b/packages/core/src/__tests__/test-generator.ts index b13a1fe414..2ff17067c8 100644 --- a/packages/core/src/__tests__/test-generator.ts +++ b/packages/core/src/__tests__/test-generator.ts @@ -285,6 +285,7 @@ const ANGULAR_TESTS: Tests = { dynamicComponentWithEventArg: getRawFile( './data/angular/dynamic-component-with-event-args.raw.tsx', ), + twoForsTrackBy: getRawFile('./data/angular/two-fors.raw.tsx'), }; const CONTEXT_TEST: Tests = { diff --git a/packages/core/src/generators/angular/index.ts b/packages/core/src/generators/angular/index.ts index 00ff975b4d..631cb9f180 100644 --- a/packages/core/src/generators/angular/index.ts +++ b/packages/core/src/generators/angular/index.ts @@ -340,9 +340,30 @@ export const blockToAngular = ({ if (checkIsForNode(json)) { const indexName = json.scope.indexName; - str += ``; + const forName = json.scope.forName; + + // Check if "key" is present for the first child of the for loop + if (json.children[0].bindings && json.children[0].bindings.key?.code) { + const fnIndex = (root.meta?._trackByForIndex as number) || 0; + const trackByFnName = `trackBy${ + forName ? forName.charAt(0).toUpperCase() + forName.slice(1) : '' + }${fnIndex}`; + root.meta._trackByForIndex = fnIndex + 1; + let code = json.children[0].bindings.key?.code; + + root.state[trackByFnName] = { + code: `${trackByFnName}(${indexName ?? '_'}, ${forName}) { return ${code}; }`, + type: 'method', + }; + + str += ``; + } else { + str += ``; + } str += json.children .map((item) => blockToAngular({ root, json: item, options, blockOptions })) .join('\n'); @@ -529,6 +550,7 @@ const handleBindings = ( if (forName) { if (item.name === 'For') continue; + if (key === 'key') continue; if (key.startsWith('on')) { const { arguments: cusArgs = ['event'] } = item.bindings[key]!; @@ -837,6 +859,15 @@ export const componentToAngular: TranspilerGenerator = stripMetaProperties(json); + const { components: dynamicComponents, dynamicTemplate } = traverseToGetAllDynamicComponents( + json, + options, + { + childComponents, + nativeAttributes: useMetadata?.angular?.nativeAttributes ?? [], + }, + ); + const dataString = getStateObjectStringFromComponent(json, { format: 'class', valueMapper: processAngularCode({ @@ -848,15 +879,6 @@ export const componentToAngular: TranspilerGenerator = }), }); - const { components: dynamicComponents, dynamicTemplate } = traverseToGetAllDynamicComponents( - json, - options, - { - childComponents, - nativeAttributes: useMetadata?.angular?.nativeAttributes ?? [], - }, - ); - const hostDisplayCss = options.visuallyIgnoreHostElement ? ':host { display: contents; }' : ''; const styles = css.length ? [hostDisplayCss, css].join('\n') : hostDisplayCss;