Issue
EDIT: REPL for answer https://svelte.dev/repl/eb7616fd162a4829b14a778c3d1627e4?version=3.48.0
What I'm talking would render this:
First we have a button:
<button on:click={add}> Add </button>
<div id="columnflexbox">
When I click it, this should happen:
<button on:click={add}> Add </button>
<!-- This exists in DOM-->
<div id="columnflexbox">
<!-- This div and components get rendered, the Div does not exist in DOM -->
<div class="row" style="display:flex;flex-direction:row">
comp1 (instance1)
comp2 (instance1)
</div>
When I click it again, another row gets added (with new instances): Add
<div id="columnflexbox">
<div class="row" style="display:flex;flex-direction:row">
comp1 (instance1)
comp2 (instance1)
</div>
<!-- Second div is generated, it does not exist in DOM, new instances of components -->
<div class="row" style="display:flex;flex-direction:row">
comp1 (instance2)
comp2 (instance2)
</div>
</div>
There is an interface:
export interface complexObject {
comp1 : ComplexObj1
comp2: ComplexObj2
}
let row: complexObject[] = []
Add function:
function add(){
let newObj:complexObject = {
comp1: new Comp1({target: div}), // I have to add a target here, or I get compile error, but how since the element doesn't exist?
comp2: new Comp2({target: div})
}
row.push(newObj);
}
I would use this way of doing it, but I can't since I'm getting compile error without adding target:
{#each row as rowitem }
<div class="row">
{rowitem.comp1}
{rowitem.comp2}
</div>
{/each}
Edit: It turns out that the styling gets applied correctly when I add the target as the html specified in the render as so:
Add function:
function add(){
let div = document.createElement("div");
div.setAttribute('class',"row")
let newObj:complexObject = {
comp1: new Comp1({target: div}),
comp2: new Comp2({target: div})
}
row.push(newObj);
}
{#each row as rowitem }
<div class="row">
{rowitem.comp1}
{rowitem.comp2}
</div>
{/each}
Now the problem is that the components do not get rendered, what I get instead is
[object Object] [object Object]
When I try to render as such:
<svelte:component this={rowitem.comp1}>
</svelte:component>
I get error:
TypeError: l is not a constructor
If I try to modify Add function and remove new keyword I get this:
Type 'typeof comp1__SvelteComponent_' is missing the following properties from type 'comp1__SvelteComponent_': $$prop_def, $$events_def, $$slot_def, $on, and 5 more.ts(2740)
Turns out that this is a problem with specifying the interface, it should be specified like so:
export interface complexObject {
comp1 : typeof ComplexObj1
comp2: typeof ComplexObj2
}
Solution
For this, one would usually use svelte:component which uses the constructor of the component as input and any props one may want to pass along. e.g.
<script>
import Comp from './Comp.svelte';
let components = [
[Comp, { content: 'Initial' }],
[Comp, { content: 'Initial 2' }],
];
function add(component, props) {
components = [...components, [component, props]];
}
</script>
<button type=button on:click={() => add(Comp, { content: 'Added' })}>
Add
</button>
{#each components as [component, props]}
<svelte:component this={component} {...props}>
(Slotted content)
</svelte:component>
{/each}
Example with types:
<script lang="ts">
import type { SvelteComponent, SvelteComponentTyped } from 'svelte';
import Comp from './Comp.svelte';
import Comp2 from './Comp2.svelte';
let components: [typeof SvelteComponent, Record<string, any>][] = [
[Comp, { content: 'Initial' }],
[Comp2, { color: 'blue' }],
];
function add<T extends typeof SvelteComponentTyped<P, any, any>, P>(
component: T,
props: P
) {
components = [...components, [component, props]];
}
</script>
add enforces the consistency between the component and its props, the array cannot, at least when using tuples. If each item were a class, the class could enforce its internal type consistency.
Answered By - H.B.
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.