Ilya V. Schurov
Ilya V. Schurov

Reputation: 8047

Render several mermaid diagrams added by javascript

I have a dynamic webpage that can contain several mermaid diagrams. These diagrams are embedded into a webpage as a source code (e.g. in <pre> tags) and then should be processed by mermaid to be replaced with the actual diagrams. Currently, I have two problems:

  1. The approach that I found (adapting answers to this question) does not work with the latest version of mermaid.

  2. It does not work with several diagrams, only the last one is processed.

Here is what I have now. I mock the script that adds diagrams with add_diagram. Then, if I run make_diagrams(), only the second one is rendered. Also, it doesn't work correctly if I switch to the latest version of mermaid.

function add_diagram() {
  diagram_code = `
  <pre class="mermaid">
    graph TD
    A[First diagram] --> B[Something]
  </pre>
  <pre class="mermaid">
    graph TD
    A[Second diagram] --> B[Something]
  </pre>
  `;
  document.getElementById("output").innerHTML += diagram_code;
}
function make_diagrams() {
  $("pre.mermaid").each(function() {
    mermaid.render(
      "body", 
      this.textContent, 
      (function (code) {this.outerHTML = code}).bind(this))
  })
}
<div id="output"/>
<button onclick="add_diagram()">add diagram</button>
<button onclick="make_diagrams()">make diagrams</button>
<script src="https://unpkg.com/mermaid@8/dist/mermaid.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>

How to make it correctly?

Upvotes: 0

Views: 1953

Answers (1)

muka.gergely
muka.gergely

Reputation: 8329

The problem that you are facing is that the second diagram is rendered with the same ID as the first one - this is overwriting the content. You need to render all diagrams with a unique ID.

Also, I'd suggest that do not use onclick, especially if you are already using jQuery.

function addDiagram() {
  return `
  <pre class="mermaid">
    graph TD
    A[First diagram] --> B[Something]
  </pre>
  <pre class="mermaid">
    graph TD
    A[Second diagram] --> B[Something]
  </pre>
  `;
}

$(".add-diagram").on("click", function() {
  $("#output").html(addDiagram())
})

const appendDiagramTo = (el) => (code) => el.outerHTML = code

function renderDiagram(id, el) {
  mermaid.render(
    id,
    el.textContent,
    appendDiagramTo(el)
  )
}

$(".make-diagrams").on("click", function() {
  $("pre.mermaid").each(function(i, e) {
    // creating the container ID -> this is NOT unique, so if you have
    // multiple places on your page rendering multiple diagrams, you
    // should update this to be really unique
    const containerId = `mermaid-${i}`

    // rendering the diagram with the unique ID
    renderDiagram(containerId, e)
  })

})
<div id="output"></div>
<button class="add-diagram">add diagram</button>
<button class="make-diagrams">make diagrams</button>
<script src="https://unpkg.com/mermaid@8/dist/mermaid.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>

Upvotes: 1

Related Questions