0

As you probably know - Polymer prohibits the unescapedHTML binding for many reasonable reasons.

How to inject HTML into a template with polymer

How to display html inside template?

However in my project it was a requirement to apply HTML from external source.

Therefore I've implemented a component named <echo-html>:

<dom-module id="echo-html">
    <template>
        <style>
        </style>
    </template>
</dom-module>

<script>
(function() {
    Polymer({
        is: 'echo-html',
        properties: {
            html: {
                type: Object,
                value: '',
                observer: '_refreshHtml'
            },
        },

        _refreshHtml: function() {
            if (this.html) {
                var value = '';
                var container = Polymer.dom(this).parentNode;

                if ((this.html.constructor == Array) && (this.html.length == 1)) {
                    value = this.html[0];
                } else  {
                    value = this.html;
                }
                if (this.parentNode) {
                    this.outerHTML = value;
                }

                this.scopeSubtree(container, true);
                $(this).removeClass('echo-html');
            }
        },
    });
})();
</script>

The problem I have is this component binds exactly the pure HTML, so when I want to use <p> or <strong> or any other element, I can't simply use parent's component styling and therefore needs to use global styles.

Is there any way to apply styles of parent element, so for example:

<parent-element>
    <echo-html html$="{{some-nasty-html}}"></echo-html>
</parent-element>

The "some-nasty-html" will include .parent-element class on it?

Is there any way I can remove the .echo-html class as well? Actually this is my question :)

Community
  • 1
  • 1

2 Answers2

1

Use the Polymer.dom() API to tell the polymer library your scopes in Shady DOM, manipulating on a Node or Element would not trigger the style scoping:

Polymer.dom(this).innerHTML = '<p>My Paragraph!</p>';

With Shadow DOM it should work without piping trough the library.

adaliszk
  • 604
  • 5
  • 18
  • Are you sure the innerHTML will apply the styles to all inherited elements? – Chris Parjaszewski Nov 15 '16 at 17:05
  • it should if you wrapping it trough the DOM API, the appendChild does work in my elements in that way, note that if you are loading an other element then the proper way to do it to importHref and then createElement – adaliszk Nov 16 '16 at 15:31
0

It seems I've made it work. I've used Polymer.dom and jQuery to access both Shadow DOM and norma DOM.

Here is the implementation I did 3-5 hrs after adding this question - hope you can use it and maybe review:

<dom-module id="echo-html">
    <template>
        <style>
        </style>
    </template>
</dom-module>

<script>
(function() {
    Polymer({
        is: 'echo-html',
        properties: {
            html: {
                type: Object,
                value: '',
                observer: '_refreshHtml'
            },
        },

        _refreshHtml: function() {
            if (this.html) {
                var value = '';
                var container = Polymer.dom(this).parentNode;
                var classList = Array.from($(container)[0].classList).filter(function(el) {
                    return ((el != 'echo-html') && (el != 'style-scope'));
                });
                var lastClass = classList[classList.length - 1];

                if ((this.html.constructor == Array) && (this.html.length == 1)) {
                    value = this.html[0];
                } else  {
                    value = this.html;
                }
                if (this.parentNode) {
                    this.outerHTML = value;
                }
                this.scopeSubtree(container, true);

                // First step - change the Shadom DOM
                Polymer.dom(container).classList.remove('echo-html');
                if (Polymer.dom(container).classList.contains(lastClass)==false) {
                    Polymer.dom(container).classList.add(lastClass);
                }

                // Second step - change the DOM
                $(container).find('*').removeClass('echo-html').addClass(lastClass);
            }
        },
    });
})();
</script>

Thank you for all your help!

Here is the link to the repository if you have any comments of issues: https://github.com/krzysztofp/echo-html-polymer