Search code examples
javascriptaemswagger-ui

Multiple Swagger UI components on one page


I have a requirement for loading multiple Swagger-UI components on one page on AEM6.5.

My component template in AEM6.5 looks like this:

<sly data-sly-use.model="xxx.aem.component.content.SwaggerModel"
     data-sly-use.template="core/wcm/components/commons/v1/templates.html"
     data-sly-use.clientlib="/libs/granite/sightly/templates/clientlib.html">
</sly>

<sly data-sly-call="${clientlib.all @ categories='xxx.ui.swagger-ui'}"/>

<sly data-sly-call="${template.placeholder @ isEmpty=!model.defined}"></sly>

<div data-sly-test="${model.defined}">
    <h1 class="t-title">
        ${model.title}
    </h1>
    <div id="${model.uniqueId}"></div>
    <sly data-sly-test="${model.defined}" data-sly-call="${swaggerScript @ path=model.swaggerYamlPath, name=model.swaggerYamlName, dom_id=model.uniqueId}"></sly>

</div>
<template data-sly-template.swaggerScript="${ @ path, name, dom_id}">
    <script>
        window.onload = function () {

            window.ui = SwaggerUIBundle({
                urls: [
                    {url: "${path @ context='text'}", name: "${name @ context='text'}"},
                ],
                dom_id: '#${dom_id @ context='text'}',
                deepLinking: true,
                filter: true,
                presets: [
                    SwaggerUIBundle.presets.apis,
                    SwaggerUIStandalonePreset
                ],
                plugins: [
                    SwaggerUIBundle.plugins.DownloadUrl
                ],
                layout: 'StandaloneLayout'
            });

        };
    </script>
</template>

The problem is that no matter I use the unique ID only one swagger component will render on the page and the other will not. I can see the swagger components are correctly loaded in the DOM but as already mentioned only one will render. In the example below only the id="swagger-ui-1110306185" will render and id="swagger-ui-1671020283" will not render.

<div class="swagger">
    
    
    
        
    <link rel="stylesheet" href="/etc.clientlibs/xxx/clientlibs/static/swagger-ui.min.css" type="text/css">
    <script src="/etc.clientlibs/xxx/clientlibs/static/swagger-ui.min.js"></script>
    
    
    
    
    
        
    
    
    <div>
        <h1 class="t-title">
            Here goes the optional title for the Swagger component
        </h1>
        <div id="swagger-ui-1671020283"></div>
        
        <script>
            window.onload = function () {
    
                window.ui = SwaggerUIBundle({
                    urls: [
                        {url: "/content/dam/yaml-files/account-information-service-api-v2-of-fi.yaml", name: "account-information-service-api-v2-of-fi"},
                    ],
                    dom_id: '#swagger-ui-1671020283',
                    deepLinking: true,
                    filter: true,
                    presets: [
                        SwaggerUIBundle.presets.apis,
                        SwaggerUIStandalonePreset
                    ],
                    plugins: [
                        SwaggerUIBundle.plugins.DownloadUrl
                    ],
                    layout: 'StandaloneLayout'
                });
    
            };
        </script>
    
    
    </div>
    </div>
   
        
            
<div class="swagger">
    
    
    
        
    
    
    
    
    
        
    
    
    <div>
        <h1 class="t-title">
            
        </h1>
        <div id="swagger-ui-1110306185"></div>
        
        <script>
            window.onload = function () {
    
                window.ui = SwaggerUIBundle({
                    urls: [
                        {url: "/content/dam/yaml-files/consent-flow-api-v2-of-fi.yaml", name: "consent-flow-api-v2-of-fi"},
                    ],
                    dom_id: '#swagger-ui-1110306185',
                    deepLinking: true,
                    filter: true,
                    presets: [
                        SwaggerUIBundle.presets.apis,
                        SwaggerUIStandalonePreset
                    ],
                    plugins: [
                        SwaggerUIBundle.plugins.DownloadUrl
                    ],
                    layout: 'StandaloneLayout'
                });
    
            };
        </script>
    
    
    </div>

</div>

Solution

  • Here is what worked:

    AEM Template:

    <div data-sly-test="${model.defined}" data-sly-attribute="${model.dataAttributes}">
            <h1 class="t-title">
                ${model.title}
            </h1>
            <div id="${model.uniqueId}"></div>
    </div>
    

    AEM TypeScript:

    declare global {
        const SwaggerUIStandalonePreset: any;
        const SwaggerUIBundle: any;
    }
    
    export class Swagger {
    
        static ID = 'swagger';
    
        static selectors = {
            self: `[data-${CoreComponentUtil.NS}-is='${Swagger.ID}']`,
        };
    
        private config: CompConfig;
        private name: string;
        private path: string;
        private domId: string;
    
        constructor(config: CompConfig) {
            this.init(config);
        }
    
        private init(config: CompConfig): void {
            this.config = config;
    
            // prevents multiple initialization
            config.element.removeAttribute(`data-${CoreComponentUtil.NS}-is`);
    
            this.name = config.element.getAttribute('data-swagger-name');
            this.path = config.element.getAttribute('data-swagger-path');
            this.domId = config.element.getAttribute('data-swagger-dom-id');
            try {
                new SwaggerUIBundle({
                    urls: [
                        {url: this.path, name: this.name},
                    ],
                    dom_id: '#' + this.domId,
                    deepLinking: true,
                    filter: true,
                    presets: [
                        SwaggerUIBundle.presets.apis,
                        SwaggerUIStandalonePreset,
                    ],
                    plugins: [
                        SwaggerUIBundle.plugins.DownloadUrl,
                    ],
                    layout: 'StandaloneLayout',
                });
            } catch (e) {
                console.log('Could not create Swagger object for ' + this.path);
            }
        }
    
    }
    
    onReady(() => {
        initComponent(Swagger);
    });
    

    AEM Model:

     public String getSwaggerYamlPath() {
            return swaggerYamlPath;
        }
    
        public String getSwaggerYamlName() {
            return parseYamlFileName(swaggerYamlPath);
        }
    
        public String getUniqueId() {
            return new StringBuilder().append("swagger-ui").append("-").append(String.valueOf(Math.abs(resource.getPath().hashCode() - 1))).toString();
    
        }
    
        @Override
        public Map<String, String> getDataAttributes() {
            Map<String, String> attributes = new HashMap<>(super.getDataAttributes());
            if (isDefined()) {
                attributes.put("data-swagger-name", getSwaggerYamlName());
                attributes.put("data-swagger-path", getSwaggerYamlPath());
                attributes.put("data-swagger-dom-id", getUniqueId());
            }
            return attributes;
        }