Skip to content

Commit

Permalink
proper list items cleanup (#179)
Browse files Browse the repository at this point in the history
  • Loading branch information
lifeart authored Dec 27, 2024
1 parent 0661e11 commit 6a2f217
Show file tree
Hide file tree
Showing 9 changed files with 91 additions and 9 deletions.
5 changes: 4 additions & 1 deletion plugins/utils.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand Down Expand Up @@ -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;
}
}
Expand Down
48 changes: 47 additions & 1 deletion src/tests/integration/each-test.gts
Original file line number Diff line number Diff line change
@@ -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) {
Expand All @@ -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 <template>
<div class='text-white p-3'>
<button type='button' {{on 'click' toggle}}>toggle</button>
<ul>
{{#if (not isExpanded)}}
<div data-test-not-expanded>NOT EXPANDED</div>
{{else if isExpanded}}
{{#each items as |item|}}
<li data-test-item>{{item.name}}</li>
{{/each}}
{{/if}}
</ul>
</div>
</template>;
}
await render(<template><PageOne /></template>);
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(
Expand Down
4 changes: 4 additions & 0 deletions src/utils/control-flow/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[]);
}),
Expand Down Expand Up @@ -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[]);
}),
Expand Down
10 changes: 10 additions & 0 deletions src/utils/helpers/-private.ts
Original file line number Diff line number Diff line change
@@ -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;
}
}
9 changes: 8 additions & 1 deletion src/utils/helpers/and.ts
Original file line number Diff line number Diff line change
@@ -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;
});
}
6 changes: 4 additions & 2 deletions src/utils/helpers/eq.ts
Original file line number Diff line number Diff line change
@@ -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);
}
7 changes: 4 additions & 3 deletions src/utils/helpers/if.ts
Original file line number Diff line number Diff line change
@@ -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;
}
5 changes: 5 additions & 0 deletions src/utils/helpers/not.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { isTag } from "./-private";

export function $__not(arg: unknown) {
if (isTag(arg)) {
return !arg.value;
}
return !arg;
}

6 changes: 5 additions & 1 deletion src/utils/helpers/or.ts
Original file line number Diff line number Diff line change
@@ -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;
});
}

0 comments on commit 6a2f217

Please sign in to comment.