Skip to content

Elements created with map added outside target slot #897

@davidrleonard

Description

@davidrleonard

Stencil version:

@stencil/core@0.9.1

I'm submitting a:

[x ] bug report
[ ] feature request
[ ] support request => Please do not submit support requests here, use one of these channels: https://forum.ionicframework.com/ or https://stencil-worldwide.slack.com

Current behavior:

  1. Use map inside of a render() function to iterate over state data, create elements, and pass the elements into a slot
  2. When the component first mounts the resulting elements are correctly rendered in the slot, and have a parentElement of the slot's owner
  3. Add something to the state data so render runs again and the map runs again
  4. The new elements are not rendered into their slot, and have a parentElement of null. They new elements are weirdly appended to the end of the slot owner's shadow root, and do not appear in the slot owner's children list. The new elements appear visually after all of their slot owner's shadow root content. The elements that were created before stay in the same place and work as expected.

Expected behavior:

1-3: Same
4. The new elements are rendered into their slot just like the original elements. The new elements have a parentElement of the slot owner and appear visually in the correct place.

Steps to reproduce:

  1. Create a stencil-component-starter project with the following files:
src/components/
├── my-app/
│   └── my-app.tsx
├── friends-list/
│   └── friends-list.tsx
└── index.html
  1. Add source code for index.html:
<!DOCTYPE html>
<html dir="ltr" lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=5.0">
  <title>Stencil Component Starter</title>
  <script src="/build/mycomponent.js"></script>

</head>
<body>
  <my-app></my-app>
</body>
</html>
  1. Add source code for my-app.tsx:
import { Component, State } from '@stencil/core';

@Component({
  tag: 'my-app',
  shadow: true
})
export class MyApp {
  @State() friends: string[] = ['Maria', 'Jasmine', 'Juan'];

  addFriend = () => {
    this.friends = [
      ...this.friends,
      'Alexander'
    ];
  }

  render() {
    return (
      <div>
        <button onClick={this.addFriend}>Add a friend</button>
        <friends-list>
          {this.friends.map(friend => {
            return <p>{friend}</p>;
          })}
        </friends-list>
      </div>
    );
  }
}
  1. Add source code for friends-list.tsx:
import { Component } from '@stencil/core';

@Component({
  tag: 'friends-list',
  shadow: true
})
export class FriendsList {
  render() {
    return (
      <div>
        <h1>These are my friends:</h1>
        <div style={{ display: 'block', border: '1px solid red' }}>
          <slot></slot>
        </div>
        <p>That's it....</p>
      </div>
    );
  }
}
  1. Run the dev server: npm run dev and open the demo in Chrome
  2. Click the "Add Friend" button
  3. The new friend "Alexander" appears outside of the red-bordered slot area.

image

  1. Inspect element and check the "Alexander" p tag's parentElement. It is null.

image

Related code:
See above.

Other information:

OS: macOS Sierra 10.13.2
Browser: Chrome Stable Version 66.0.3359.181 (Official Build) (64-bit)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions