We would like to add a counter to our Builder carousel component, to show the user they are on Slide X of Y. Is this possible? Could it be done with some custom javascript?
@Canuckaholic definitely, this shouldn’t be too complicated, and there are many ways you could do it. You could create your own custom component that includes this logic, or if you wanted to still use the Builder component you could just add some custom JS in the Custom JS + CSS window:
Hopefully that gives you a few directions you could go…Take a look and try it out and let us know if you have any follow up questions!
Thanks for the quick reply! We are on the same page in that I am looking to add some custom JS in the Custom JS + CSS window, however the trick is going to be determining how many slides have been added to the carousel in order to show the user they are on slide 5 / 7, for example. So my custom JS code is going to need some information from the carousel in order to display the right numbers.
One idea I have is to use the Content API, fetch my symbols (my carousel is in a symbol), and then count the number of slides in the JSON result for the carousel object.
Is there a way to use the Content API (ie. do a fetch) directly from inside Builder?
@Canuckaholic that would work. You could hit the Content API in a fetch() within the JS+CSS window
await fetch(someUrl)
.then(res => res.json())
.then(data => {
// set the data on the state object so you can access it from your components
state.someData = data;
});
or add it as an API call in the +API Data section, but I think the most straight forward way could be to just add a class name to each carousel slide in the CSS Class section of the Style tab
and then you can grab the items using document.getElementsByClassName(className).length
and use that to figure out the length and where you are within the carousel, etc.
Let me know if that works for you!
I have the following code almost working. What I did is add my Carousel symbol as a data source for itself using the “Connect data from popular sources” section. It works if I edit the JS, close the edit window, and see the UI respond. However, I’m noticing that state.symbol
is undefined on page load, so it doesn’t actually work.
var blocks = state.symbol?.data?.blocks
if (blocks?.length) {
var carousel = blocks.find(block => {
return block.component?.name === 'Builder:Carousel'
})
var currentSlide = 1
var totalSlides = carousel.component.options.slides.length
var counterEl = document.getElementById('counter')
counterEl.textContent = currentSlide + " / " + totalSlides
function incrementCount() {
currentSlide++
if (currentSlide > totalSlides) {
currentSlide = 1
}
counterEl.textContent = currentSlide + " / " + totalSlides
}
function decrementCount() {
currentSlide--
if (currentSlide < 1) {
currentSlide = totalSlides
}
counterEl.textContent = currentSlide + " / " + totalSlides
}
var nextBtn = document.getElementById('next')
nextBtn.addEventListener('click', incrementCount)
var prevBtn = document.getElementById('prev')
prevBtn.addEventListener('click', decrementCount)
}
}
I have the following in my JS, but on page load it’s not finding the elements in the DOM:
if (Builder.isBrowser) {
function getSlidesByClassName() {
return document.getElementsByClassName('slide').length
}
var totalSlides = getSlidesByClassName()
}
totalSlides is undefined when the page first loads. Could something be off with the part that waits for the DOM to be loaded before running the JS?
Well for anyone wanting to do this who stumbles upon this thread, here’s my current code that seems to work. It’s not the best implementation though, I would say, so perhaps Builder could add this feature for the carousel to their roadmap?
await fetch('https://cdn.builder.io/api/v2/content/symbol?apiKey=<API_KEY>&query.id=<COMPONENT_ID>&limit=1')
.then(res => res.json())
.then(data => {
// set the data on the state object so you can access it from your components
state.carousel = data.results
})
// In case the fetch doesn't work, we can try to get the total from the class names
function getSlidesByClassName() {
return document.getElementsByClassName('slide').length
}
var totalSlides = getSlidesByClassName()
var currentSlide = 1
var wait = false
var blocks = state.carousel?.[0].data?.blocks || state.symbol?.data?.blocks
if (blocks?.length) {
var carousel = blocks.find(block => {
return block.component?.name === 'Builder:Carousel'
})
if (carousel.component.options.slides.length) {
totalSlides = carousel.component.options.slides.length
}
}
var counterEl = document.getElementById('counter')
counterEl.textContent = currentSlide + " / " + totalSlides
function startTimer() {
wait = true
setTimeout(() => wait = false, 700)
}
function incrementCount() {
if (!wait) {
startTimer()
currentSlide++
if (currentSlide > totalSlides) {
currentSlide = 1
}
counterEl.textContent = currentSlide + " / " + totalSlides
}
}
function decrementCount() {
if (!wait) {
startTimer()
currentSlide--
if (currentSlide < 1) {
currentSlide = totalSlides
}
counterEl.textContent = currentSlide + " / " + totalSlides
}
}
var nextBtn = document.getElementById('next')
nextBtn.addEventListener('click', incrementCount)
var prevBtn = document.getElementById('prev')
prevBtn.addEventListener('click', decrementCount)