Developer forum

Forum » CMS - Standard features » Global:Paragraph.Content in DW10 cshtml

Global:Paragraph.Content in DW10 cshtml

NC
NC
Reply

Hi,

what are the right code to place the content from a specific paragraphID inside a random template?

In the good old days with DW9 and html it was @Global:Paragraph.Content([ID])

But how can I do it today?

Thanx in advance...

 


Replies

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

Yup, really old days.

In all new implementations of Dynamicweb you will be using a grid - that grid sits on a page and consists of rows.

You can render the entire content of a given page - taking the entire grid and stack it on top of another using:

@RenderGrid(pageid)

You can render one row from that grid using

@RenderGridRow(rowid)

You can render a single paragraph using:

@RenderParagraphContent(123)

But really you should not do that, unless it is a footer or something like that... What would you like to render on all pages?

 
NC
NC
Reply

Hi Nicolai,

Thank you =)

The client are creating long pages with many paragraphs down the page.

They want a flowting navigation as a tab to the right, that opens/slides out when clicked and inside it shows the paragraph-headers as anchor-links and as a marker of the related paragraph.
So I was thinking of using itempublisher to list all headers of the paragraphs on that page.

..NC

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

That would be one way of solving it.

But you could also use some JS. Here generated by some AI:

Here’s a recipe for a floating, sticky Table of Contents that reads your <h1><h4> elements, nests them correctly, and links to each section—all using Bootstrap 5:


1. Add a TOC container

Place this somewhere in your page—typically in a sidebar or column:

<!-- TOC sidebar -->
<nav id="toc"
     class="position-sticky top-3 p-3 bg-light border rounded"
     style="max-height: calc(100vh - 1rem); overflow-y: auto;">
  <h5 class="mb-3">On this page</h5>
  <ul id="toc-list" class="list-unstyled"></ul>
</nav>
  • position-sticky top-3: sticks 1 rem below the navbar (adjust as needed).

  • max-height + overflow-y: keeps it scrollable if very long.

  • #toc-list: where we’ll inject the links.


2. JavaScript to generate the TOC

<script>
document.addEventListener('DOMContentLoaded', () => {
  const contentHeadings = document.querySelectorAll('h1[id], h2[id], h3[id], h4[id]');
  const tocList        = document.getElementById('toc-list');

  contentHeadings.forEach(heading => {
    // Determine nesting level (h1 → 1, h2 → 2, …)
    const level = Number(heading.tagName.charAt(1));

    // Create a link
    const link = document.createElement('a');
    link.href        = `#${heading.id}`;
    link.textContent = heading.textContent;
    link.className   = 'd-block text-decoration-none py-1';
    // indent by level: h1 no indent, h2 ms-3, h3 ms-4, etc
    link.classList.add(`ms-${(level - 1) * 3}`);

    // Wrap in an <li> (optional if you prefer a flat list)
    const li = document.createElement('li');
    li.appendChild(link);

    tocList.appendChild(li);
  });

  // Optional: highlight on scroll
  const tocLinks = tocList.querySelectorAll('a');
  const opts = { rootMargin: '0px 0px -70% 0px' };
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      const id = entry.target.id;
      const tocLink = tocList.querySelector(`a[href="#${id}"]`);
      if (entry.isIntersecting) {
        tocLinks.forEach(a => a.classList.remove('fw-bold'));
        tocLink?.classList.add('fw-bold');
      }
    });
  }, opts);

  contentHeadings.forEach(h => observer.observe(h));
});
</script>

What this does:

  1. Selects all headings (h1h4) that have an id.

  2. Creates a nested-looking link for each, indenting via Bootstrap’s margin classes (ms-3, ms-6, …).

  3. Appends each to your <ul id="toc-list">.

  4. (Optional) Uses an IntersectionObserver to add a fw-bold class to the link whose section is in view.


3. Style tweaks (optional)

/* Make sure your page content has enough left/right padding
   so the sticky nav doesn’t overlap on small screens */
body {
  padding-left: 1rem;
  padding-right: 1rem;
}

/* Narrow the TOC on wider screens */
@media (min-width: 992px) {
  #toc {
    width: 250px;
  }
}

Putting it all together

<div class="container">
  <div class="row">
    <!-- TOC -->
    <aside class="col-lg-3 d-none d-lg-block">
      <!-- (insert the TOC <nav> from step 1 here) -->
    </aside>

    <!-- Main content -->
    <main class="col-12 col-lg-9">
      <!-- Your h1–h4 content goes here -->
      <h1 id="123">Section One</h1>
      <p>…</p>
      <h2 id="123-1">Subsection</h2>
      <p>…</p>
      <!-- etc. -->
      <h1 id="234">Section Two</h1>
      <!-- … -->
    </main>
  </div>
</div>
  • On large screens (lg and up), the TOC lives in the left column and sticks.

  • On smaller screens you can either hide it (d-none d-lg-block) or move it elsewhere (e.g. an Offcanvas).


That’s it! You now have a dynamic, sticky TOC that:

  • Reads your headings automatically

  • Nests them by level

  • Links to each section

  • Highlights the active section as you scroll

Feel free to tweak spacing, colors or the observer’s rootMargin to suit your design.

 
NC
NC
Reply

Thank you! 

It a smart solution if the items are different on the page.

But I'll go with the itempublisher solution + bootstrap Scrollspy if I can get the paragraphID for each item through the itempublisher.

It looks like not possible, but is there anonter way to get paragraphID in the loop?

Thanx in advance

..NC

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

Currently you cannot get the paragraphid.

But you do not need an item publihser. You are on the page - you can just do a template like this:

@{
 <ul>
 @foreach(var paragraph in Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(Pageview.ID))
 {
 <li>
 <a href="#@paragraph.ID">@paragraph.Header</a>
 <small>@paragraph?.Item?["SomeItemProperty"]</small>
 </li>
 }
 </ul>
}

 

 

 
NC
NC
Reply

Hi again,

I'm using your last suggestion. Lovely simple... but

It works for all paragraphs. Like then a row has a text paragraph and a video paragraph.
I would like it to grap only the text paragraphs.
Or another option... to show only the paragraphs that has a Title (Video don't have a title).

Related problem with a question:
The scrollspy from bootstrap work by ids.
Is there a way to add a letter in front of the number in the id?
The browser doesn't handel that correctly — because #22070 isn’t a valid CSS selector.

Thanx in advance =)
..NC

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

The ID and CSS selector is discussed here: https://github.com/dynamicweb/DynamicWeb/issues/332

You can escape the CSS selector - so "#22070" becomes "#\32 2070" when used in CSS files. If they are not used in CSS files. My guess is that you need to do it in JS - you can do 

document.getElementById('22070')

But if you use querySelector, you can do it like this:
 

document.querySelector('[id="22070"]');

Here is an online CSS selector escape tool: https://mothereff.in/css-escapes

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply

Here are some ideas for filtering the list of paragraphs:

<ul>
 @foreach (var paragraph in Dynamicweb.Content.Services.Paragraphs.GetParagraphsByPageId(Pageview.ID))
 {
 // Example of how to filter paragraphs based on ItemType
 if (paragraph.ItemType == "Swift-v2_Text" || paragraph.ItemType == "Swift-v2_TextAndImage")
 {
 <li>

<a href="#@paragraph.ID">@paragraph.Header</a>
 <div>@paragraph.ItemType</div>
 <small>@paragraph?.Item?["SomeItemProperty"]</small>
 </li>
 }

// Example of how to create a ViewModel for a paragraph and check for a specific property
 var p = ContentViewModelFactory.CreateParagraphInfoViewModel(paragraph);
 @if (p.Item.TryGetString("Title", out string title))
 {
 <li>

<a href="#@p.ID">@title</a>
 <small>@p.Item.GetValue("SomeItemProperty")</small>
 </li>
 }
 }
</ul>
 
Adrian Ursu Dynamicweb Employee
Adrian Ursu
Reply

Hi NC,

Your use case seems close to an "Anchor navigation".

I have faced similar challenges as yours and I ended up creating a dedicated Row ItemType for the "Anchors".
Then, I used some logic to list all rows of the particular ItemType in a list.

The PROs:
Control over ID and heading

The CONs:

You have to define a specific element instead of using the content.

Adrian

 
NC
NC
Reply

Thank you guys! Much appreciated =)

I'm trying to keep the standard swift as long as possible.
Sometimes easier than others...

Love your inputs THANX
..NC

 

You must be logged in to post in the forum