diff --git a/plugins/utils.ts b/plugins/utils.ts
index d51f124..7715bea 100644
--- a/plugins/utils.ts
+++ b/plugins/utils.ts
@@ -1,5 +1,5 @@
import type { ASTv1 } from '@glimmer/syntax';
-import { SYMBOLS } from './symbols';
+import { EVENT_TYPE, SYMBOLS } from './symbols';
import type { Flags } from './flags';
import type { ComplexJSType } from './converter';
@@ -340,6 +340,9 @@ function hasStableChildsForControlNode(
if ('isControl' in child) {
hasStableChild = false;
} else {
+ if (child.events.filter(([id]) => id === EVENT_TYPE.ON_CREATED).length) {
+ return false;
+ }
hasStableChild = true;
}
}
diff --git a/src/tests/integration/each-test.gts b/src/tests/integration/each-test.gts
index 6aee7bb..a742d2d 100644
--- a/src/tests/integration/each-test.gts
+++ b/src/tests/integration/each-test.gts
@@ -1,7 +1,7 @@
import { module, test } from 'qunit';
import { render, rerender, click } from '@/tests/utils';
import { cell } from '@lifeart/gxt';
-import { type Cell } from '@/utils/reactive';
+import { formula, type Cell } from '@/utils/reactive';
import { step } from '../utils';
module('Integration | InternalComponent | each', function (hooks) {
@@ -21,6 +21,52 @@ module('Integration | InternalComponent | each', function (hooks) {
}
}
+ test('it properly remove all list items if its rendered with update', async function (assert) {
+ function toNamedObject(arr: number[]) {
+ return arr.map((el) => {
+ return { name: el };
+ });
+ }
+ const items = cell(toNamedObject([1]));
+ const isFirstRender = cell(true);
+
+ function PageOne() {
+ const isExpanded = formula(() => {
+ return items.value.length === 3 || isFirstRender.value === true;
+ });
+ const toggle = () => {
+ if (items.value.length === 3) {
+ items.update(toNamedObject([2]));
+ } else {
+ items.update(toNamedObject([1, 2, 3]));
+ }
+ };
+ return
+
+
+
+ {{#if (not isExpanded)}}
+ NOT EXPANDED
+ {{else if isExpanded}}
+ {{#each items as |item|}}
+ - {{item.name}}
+ {{/each}}
+ {{/if}}
+
+
+ ;
+ }
+ await render();
+ assert.dom('[data-test-item]').exists({ count: 1 }, 'Render first item');
+ items.update(toNamedObject([1, 2, 3]));
+ isFirstRender.update(false);
+ await rerender();
+ assert.dom('[data-test-item]').exists({ count: 3 }, 'Render all items');
+ await click('button');
+ assert.dom('[data-test-item]').doesNotExist('No list tails left');
+ assert.dom('[data-test-not-expanded]').exists({ count: 1 }, 'if toggled');
+ });
+
test('remove first element', async function (assert) {
const amountOfItemsToTest = 10;
const items = cell(
diff --git a/src/utils/control-flow/list.ts b/src/utils/control-flow/list.ts
index 1fcb132..d023a41 100644
--- a/src/utils/control-flow/list.ts
+++ b/src/utils/control-flow/list.ts
@@ -344,6 +344,7 @@ export class SyncListComponent<
) {
super(params, outlet, topMarker);
associateDestroyable(params.ctx, [
+ () => this.syncList([]),
opcodeFor(this.tag, (value) => {
this.syncList(value as T[]);
}),
@@ -426,6 +427,9 @@ export class AsyncListComponent<
) {
super(params, outlet, topMarker);
associateDestroyable(params.ctx, [
+ async () => {
+ await this.syncList([]);
+ },
opcodeFor(this.tag, async (value) => {
await this.syncList(value as T[]);
}),
diff --git a/src/utils/helpers/-private.ts b/src/utils/helpers/-private.ts
new file mode 100644
index 0000000..06943c0
--- /dev/null
+++ b/src/utils/helpers/-private.ts
@@ -0,0 +1,10 @@
+import type { AnyCell } from "../reactive";
+import { isTagLike } from "../shared";
+
+export function isTag(arg: unknown): arg is AnyCell {
+ if (typeof arg === 'object' && arg !== null && isTagLike(arg)) {
+ return true;
+ } else {
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/src/utils/helpers/and.ts b/src/utils/helpers/and.ts
index e64cd12..0d93281 100644
--- a/src/utils/helpers/and.ts
+++ b/src/utils/helpers/and.ts
@@ -1,3 +1,10 @@
+import { isTag } from "./-private";
+
export function $__and(...args: unknown[]) {
- return args.every((arg) => !!arg);
+ return args.every((arg) => {
+ if (isTag(arg)) {
+ return !!arg.value;
+ }
+ return !!arg;
+ });
}
diff --git a/src/utils/helpers/eq.ts b/src/utils/helpers/eq.ts
index faf3fee..1e1d07a 100644
--- a/src/utils/helpers/eq.ts
+++ b/src/utils/helpers/eq.ts
@@ -1,4 +1,6 @@
+import { isTag } from "./-private";
+
export function $__eq(...args: unknown[]) {
- const firstValue = args[0];
- return args.every((arg) => arg === firstValue);
+ const firstValue = isTag(args[0]) ? args[0].value : args[0];
+ return args.every((arg) => (isTag(arg) ? arg.value : arg) === firstValue);
}
diff --git a/src/utils/helpers/if.ts b/src/utils/helpers/if.ts
index 0c28b26..765099b 100644
--- a/src/utils/helpers/if.ts
+++ b/src/utils/helpers/if.ts
@@ -1,11 +1,12 @@
-import { type AnyCell } from '../reactive';
+import { isTag } from "./-private";
+
export function $__if(
condition: unknown,
ifTrue: unknown,
ifFalse: unknown = '',
) {
- if (typeof condition === 'object') {
- return (condition as AnyCell).value ? ifTrue : ifFalse;
+ if (isTag(condition)) {
+ return condition.value ? ifTrue : ifFalse;
}
return condition ? ifTrue : ifFalse;
}
diff --git a/src/utils/helpers/not.ts b/src/utils/helpers/not.ts
index 4bef1f7..2771ad7 100644
--- a/src/utils/helpers/not.ts
+++ b/src/utils/helpers/not.ts
@@ -1,4 +1,9 @@
+import { isTag } from "./-private";
+
export function $__not(arg: unknown) {
+ if (isTag(arg)) {
+ return !arg.value;
+ }
return !arg;
}
\ No newline at end of file
diff --git a/src/utils/helpers/or.ts b/src/utils/helpers/or.ts
index fd9d773..213581e 100644
--- a/src/utils/helpers/or.ts
+++ b/src/utils/helpers/or.ts
@@ -1,4 +1,8 @@
+import { isTag } from "./-private";
+
export function $__or(...args: unknown[]) {
- return args.find((arg) => !!arg);
+ return args.find((arg) => {
+ return isTag(arg) ? !!arg.value : !!arg;
+ });
}
\ No newline at end of file