Skip to content

Initialize custom elements in connectedCallback #5139

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
07e2dde
Initialize custom elements in connected callback
Jul 9, 2020
3c69b17
Refactor $$setup function
Jul 13, 2020
8be9968
Fix props-after-create test
Jul 13, 2020
61b596c
Revert changes to props test
Jul 13, 2020
142bd91
Remove logging
Jul 13, 2020
83a86d0
Update expected output for css-shadow-dom-keyframes
Jul 13, 2020
db80d0c
Revert accidental changes
Jul 13, 2020
721c9c5
Revert accidental changes
Jul 13, 2020
911e15d
Use DOM, remove async from props-after-create test
Jul 14, 2020
12c51f3
site: remove an obsolete TODO in blog post (#5135)
mindrones Jul 13, 2020
04871ae
site: add FAQ entry for how to document a svelte component (#5131)
orta Jul 13, 2020
2d6324e
fix $$props reactive for slots (#5125)
tanhauhau Jul 13, 2020
fda1b35
Simplify each block bindings example (#5094)
CyberAP Jul 14, 2020
471c0d2
site: use https in link in blog (#5148)
axil Jul 14, 2020
f59a8a8
invalidate $$props and $$restProps only when there are changes (#5123)
tanhauhau Jul 14, 2020
269354a
Fixes #5153 (#5154)
Wolfr Jul 17, 2020
4bd1de6
Bump lodash from 4.17.15 to 4.17.19 in /site (#5155)
dependabot[bot] Jul 17, 2020
179d9ff
Bump lodash from 4.17.15 to 4.17.19 (#5152)
dependabot[bot] Jul 17, 2020
c3da9e4
add updating guard to binding callback (#5126)
tanhauhau Jul 17, 2020
3d81b8c
site: explain how to use `site-kit` and `site-repl` (#5163)
benschac Jul 20, 2020
453c727
site: rephrase to clarify that actions can have just one parameter.
mindrones Jul 21, 2020
b1c18c7
Initial stab at a TypeScript blog post (#5101)
orta Jul 21, 2020
9d6769b
tweak blog post anchor style to be less noisy
Rich-Harris Jul 21, 2020
a63f722
diff highlighting
Rich-Harris Jul 21, 2020
74515cb
site: update links in the Sapper intro blog post (#5189)
rmacklin Jul 24, 2020
b862483
better error message for mismatched tags due to autoclosing (#5060)
tanhauhau Jul 24, 2020
bf0a2dc
fix bind:group contextual reference (#5199)
tanhauhau Jul 24, 2020
0b09c70
site: fix escaping in RSS feed (#5214)
habibrosyad Jul 28, 2020
1955089
site: use relative link to tutorial in FAQ entry
Conduitry Jul 28, 2020
c906e21
site: clarify file -> module in <svelte:self> tutorial (#5171)
Jul 30, 2020
f537cfe
Merge branch 'master' into initialize-custom-elements-in-connected-ca…
Aug 5, 2020
11df5ff
Fix failing test
Aug 5, 2020
ac0a72f
Merge pull request #2 from sveltejs/master
Truffula Aug 5, 2020
790857a
Merge branch 'master' into initialize-custom-elements-in-connected-ca…
Aug 5, 2020
b8de8fd
Only include type for $$setup in Component
Aug 5, 2020
e7b9025
Use is_empty
Aug 5, 2020
ab7c6bf
Use is_empty
Aug 5, 2020
f30e39e
Merge branch 'initialize-custom-elements-in-connected-callback' of ht…
Aug 5, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions src/compiler/compile/render_dom/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -462,10 +462,14 @@ export default function dom(
class ${name} extends @SvelteElement {
constructor(options) {
super();

if (options) {
this.$$setup(options);
}
}
$$setup(options) {
${css.code && b`this.shadowRoot.innerHTML = \`<style>${css.code.replace(/\\/g, '\\\\')}${options.dev ? `\n/*# sourceMappingURL=${css.map.toUrl()} */` : ''}</style>\`;`}

@init(this, { target: this.shadowRoot }, ${definition}, ${has_create_fragment ? 'create_fragment': 'null'}, ${not_equal}, ${prop_indexes}, ${dirty});
@init(this, { props: options ? options.props : null, target: this.shadowRoot }, ${definition}, ${has_create_fragment ? 'create_fragment' : 'null'}, ${not_equal}, ${prop_indexes}, ${dirty});

${dev_props_check}

Expand Down Expand Up @@ -517,7 +521,7 @@ export default function dom(
constructor(options) {
super(${options.dev && `options`});
${should_add_css && b`if (!@_document.getElementById("${component.stylesheet.id}-style")) ${add_css}();`}
@init(this, options, ${definition}, ${has_create_fragment ? 'create_fragment': 'null'}, ${not_equal}, ${prop_indexes}, ${dirty});
@init(this, options, ${definition}, ${has_create_fragment ? 'create_fragment' : 'null'}, ${not_equal}, ${prop_indexes}, ${dirty});
${options.dev && b`@dispatch_dev("SvelteRegisterComponent", { component: this, tagName: "${name.name}", options, id: create_fragment.name });`}

${dev_props_check}
Expand Down
25 changes: 25 additions & 0 deletions src/runtime/internal/Component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,15 +174,35 @@ if (typeof HTMLElement === 'function') {
this.attachShadow({ mode: 'open' });
}

// placeholder object to allow props to be set pre-$$setup
$$initialProps: Record<string, any> | null = {};
$$setup: (options) => void;

connectedCallback() {
if (!this.$$) {
// wasn't set up from constructor as options were not ready
const options = is_empty(this.$$initialProps) ?
null:
{
props: this.$$initialProps
};

this.$$setup(options);
// clean up, prevent reuse of $$initialProps
this.$$initialProps = null;
}
// @ts-ignore todo: improve typings
for (const key in this.$$.slotted) {
// @ts-ignore todo: improve typings
this.appendChild(this.$$.slotted[key]);
}
}

// initial implementation of method, will be overridden on setup
attributeChangedCallback(attr, _oldValue, newValue) {
if (this.$$initialProps) {
this.$$initialProps[attr] = newValue;
}
this[attr] = newValue;
}

Expand All @@ -203,6 +223,11 @@ if (typeof HTMLElement === 'function') {
}

$set($$props) {
if (this.$$initialProps && $$props) {
for (const attr of Object.getOwnPropertyNames($$props)) {
this.$$initialProps[attr] = $$props[attr];
}
}
if (this.$$set && !is_empty($$props)) {
this.$$.skip_bound = true;
this.$$set($$props);
Expand Down
8 changes: 8 additions & 0 deletions test/custom-elements/samples/props-after-create/main.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<svelte:options tag="custom-element"/>

<script>
export let items = [];
</script>

<p>{items.length} items</p>
<p>{items.join(', ')}</p>
28 changes: 28 additions & 0 deletions test/custom-elements/samples/props-after-create/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as assert from 'assert';
import CustomElement from './main.svelte';

export default function (target) {

// initialize without options to simulate instantiation within HTML
const el = new CustomElement();

assert.equal(el.outerHTML, '<custom-element></custom-element>');

el.items = ['a', 'b', 'c'];
const p0 = el.shadowRoot.querySelector('p');

// shouldn't be instantitated yet
assert.equal(p0, undefined);

// add to to DOM to trigger setup
target.appendChild(el);

const [p1, p2] = el.shadowRoot.querySelectorAll('p');
assert.equal(p1.textContent, '3 items');
assert.equal(p2.textContent, 'a, b, c');

el.items = ['d', 'e', 'f', 'g', 'h'];

assert.equal(p1.textContent, '5 items');
assert.equal(p2.textContent, 'd, e, f, g, h');
}
22 changes: 20 additions & 2 deletions test/js/samples/css-shadow-dom-keyframes/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,26 @@ function create_fragment(ctx) {
class Component extends SvelteElement {
constructor(options) {
super();

if (options) {
this.$$setup(options);
}
}

$$setup(options) {
this.shadowRoot.innerHTML = `<style>div{animation:foo 1s}@keyframes foo{0%{opacity:0}100%{opacity:1}}</style>`;
init(this, { target: this.shadowRoot }, null, create_fragment, safe_not_equal, {});

init(
this,
{
props: options ? options.props : null,
target: this.shadowRoot
},
null,
create_fragment,
safe_not_equal,
{}
);

if (options) {
if (options.target) {
Expand All @@ -45,4 +63,4 @@ class Component extends SvelteElement {
}

customElements.define("custom-element", Component);
export default Component;
export default Component;