Angular-Dynamic-Hooks / ngx-dynamic-hooks

Automatically insert live Angular components into dynamic strings (based on their selector or any pattern of your choice) and render the result in the DOM.
MIT License
116 stars 6 forks source link

data-attributes aren't rendered properly #4

Closed Sjeiti closed 3 years ago

Sjeiti commented 3 years ago

Data attributes seem to be stripped from regular HTML (<ngx-dynamic-hooks [content]="'<span data-foo=notrendered>aha</span>'"></ngx-dynamic-hooks>). Angular components with with data attributes seem to fail to render completely.

MTobisch commented 3 years ago

There's actually multiple layers to your issue. It can be solved, though. I'll go over them one by one:

  1. ngx-dynamic-hooks uses Angular sanitization by default, which strips any attributes from HTML that it deems risky, including data-attributes. You can disable this via the outlet options like: <ngx-dynamic-hooks [content]="..." [options]="{sanitize: false}"></ngx-dynamic-hooks>. Note, though, that this allows potentially malicious HTML to be rendered, so make sure you know where its coming from.
  2. You need to put the attribute value in single or double quotes, like: <span data-foo="notrendered">aha</span>. The default SelectorHookParser currently doesn't support the unquoted attribute value syntax.
  3. In previous versions, data-attributes didn't work because hyphens weren't recognized as valid characters for attribute names, which has now been corrected with the new version 1.5.1 (thanks for making me aware of this).

These three fixes combined will allow data-attribute binding for non-component-elements.

However, even with all of that, on component selectors it will still be no good because of the way that the library works. All it does is look for registered hooks in a given text, load their corresponding components, then look for inputs/outputs on each hook and pass them in. The hooks are then replaced in their entirety with the actual component element and anything that was on them is lost. In short, "normal" HTML attributes on selector hooks don't carry over because the library doesn't even see them, in a way.

There's an easy workaround, though: Consider simply declaring the data-attributes you need as inputs for your component. This way, the library will hand them in, and, if needed, you can use host bindings to set them as attributes (again) on the component host element.

In your example, if you created an input like @Input('data-foo') @HostBinding('attr.data-foo') dataFoo: string; in your component, the data-attribute should show up on the host element automatically.

Sjeiti commented 3 years ago

Thanks for the quick reply. My real use-case was a bit more complicated. I was using Cypress for testing where the convention is to use [data-cy="myComponent"] for element selection. The data-attribute is not a functional part of the component so I'm reluctant declaring it there. Wrapping the component like so span[data-cy="myComponent"]>my-component is an acceptable workaround though.