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...
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...
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?
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
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:
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.
<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>
Selects all headings (h1–h4) that have an id.
Creates a nested-looking link for each, indenting via Bootstrap’s margin classes (ms-3, ms-6, …).
Appends each to your <ul id="toc-list">.
(Optional) Uses an IntersectionObserver to add a fw-bold class to the link whose section is in view.
/* 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;
}
}
<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.
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
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>
}
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
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
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>
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
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