最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Import and render an html element with SolidJS - Stack Overflow

programmeradmin0浏览0评论

When my application loads, it will call the backend to obtain a description of ponents the user decides to add.

These objects should have a function to generate their html, take a button for example: it will export an html() method that returns a string containing an HTML text:

const buttonText = "I'm a button"
export default {
  html() {
    return `<button>${buttonText}</button>`
  }
}

On the frontend side, I will be using import statement to load the aforementioned button module and store it in a JSON object, sort of like a plugins manager.

When it es time to render it, I tried using Dynamic:

<For each={plugins()} fallback={<p>Loading...</p>}>{ plugin =>
  <div>
    <Dynamic ponent={plugin.module.html()}>
    </Dynamic>
  <div>
}</For>

But it falls with DOMException: Failed to execute 'createElement' on 'Document': The tag name provided ('<button>I'm a button</button>') is not a valid name.

Which makes sense since it is expecting something like a "div" element, not a string like <button>I'm a button</button>.

What would be the correct way to render HTML strings in SolidJS?

When my application loads, it will call the backend to obtain a description of ponents the user decides to add.

These objects should have a function to generate their html, take a button for example: it will export an html() method that returns a string containing an HTML text:

const buttonText = "I'm a button"
export default {
  html() {
    return `<button>${buttonText}</button>`
  }
}

On the frontend side, I will be using import statement to load the aforementioned button module and store it in a JSON object, sort of like a plugins manager.

When it es time to render it, I tried using Dynamic:

<For each={plugins()} fallback={<p>Loading...</p>}>{ plugin =>
  <div>
    <Dynamic ponent={plugin.module.html()}>
    </Dynamic>
  <div>
}</For>

But it falls with DOMException: Failed to execute 'createElement' on 'Document': The tag name provided ('<button>I'm a button</button>') is not a valid name.

Which makes sense since it is expecting something like a "div" element, not a string like <button>I'm a button</button>.

What would be the correct way to render HTML strings in SolidJS?

Share Improve this question edited Oct 27, 2022 at 20:09 snnsnn 13.7k5 gold badges49 silver badges55 bronze badges asked Oct 18, 2022 at 8:23 AndreiAndrei 171 silver badge6 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 5

A simple solution would be just to use innerHTML like so:

<For each={plugins()} fallback={<p>Loading...</p>}>
{ plugin =>
 <div innerHTML={plugin.module.html()}>
 <div>
}</For>

If you need something more interactive, perhaps using template and cloneNode which is what Solidjs piles your code to normally. Here is a full example below. I created it on the playground.

import { render, template } from "solid-js/web";
import { For } from "solid-js";

function MakeButton() {
  const plugins = ["<button>Click me</button>"];

  const handleClick = () => {
    console.log("Clicked button");
  }

  const createElem = (el: string) => {
    const elem = template(el, 2);
    const ret = elem.cloneNode(true);
    if (ret.tagName === "BUTTON") {
      ret.onclick = handleClick;
    }
    return ret;
  }

  return (<>
    <For each={plugins} fallback={<div>Loading...</div>}>
      {plugin =>
        <div>{createElem(plugin)}</div>
      }
    </For>
  </>);
}

render(() => <MakeButton />, document.getElementById("app"));

If I understand your question correctly you are trying to import a regular HTML element and render it inside a solid ponent, than answer is simple, just put it between curly brackets like any other expression. Unlike React, Solid can render an HTML element directly.

import { render } from "solid-js/web";
import { createSignal } from "solid-js";

const el = document.createElement('p');
el.innerHTML = 'Some Content';

function App() {
  return (
    <div>{el}</div>
  );
}

render(App, document.getElementById("app")!);

You don't need to use innerHTML property or you don't even need to wrap it inside a JSX element:

const el = document.createElement('p');
el.innerHTML = 'Some Content';

function App() {
  return el;
}

Few issues with your question. The html method is not returning an HTML element but a string:

const buttonText = "I'm a button"
export default {
  html() {
    return `<button>${buttonText}</button>`
  }
}

You can fix it by returning an actual Element. I called the imported object x in order to avoid code bloat since you can import any variable from another module:

const buttonText = "I'm a button";

const x = {
  html() {
    const el = document.createElement("button");
    el.innerText = buttonText;
    return el;
  },
};

function App() {
  return x.html();
}

If you are using x just to return a string, you may omit it pletely and just export the element itself:

const el = document.createElement("button");
el.innerText = buttonText;

export default el;

As an alternative you can return the string and have the DOM render for you using innerHTML property. You can either create the element yourself:

const el = document.createElement('div');
el.innerHTML = x.html();

Or have Solid do it for you:

const txt = "<button>I'm a button</button>";

function App() {
  return <div innerHTML={txt}></div>
}

Either way it has nothing to do with Solid, it is browser's feature to render a string into HTML element when assigned to an element's innerHTML. Actually it is what Solid's template function use internally.

As a side note, Solid uses clone method to render multiple elements efficiently, if you are not rendering large HTML text with with lots of elements, createElement is better since it is cleaner and faster.

"Loading ponents dynamically" refers to something totally different, so does a ponent. A dynamic ponent means the rendered output is bound to a variable rather than a condition:

const RedThing = () => <strong style="color: red">Red Thing</strong>;
const GreenThing = () => <strong style="color: green">Green Thing</strong>;
const BlueThing = () => <strong style="color: blue">Blue Thing</strong>;

const [selected, setSelected] = createSignal('red');

const options = {
  red: RedThing,
  green: GreenThing,
  blue: BlueThing
}

<Dynamic ponent={options[selected()]} />

Still you need to pass a ponent, not a string. A string containing a valid HTML text is not a JSX ponent.

It is best to express our problems in simple terms and avoid technical jargon because it makes really hard to understand.

发布评论

评论列表(0)

  1. 暂无评论