early-train-33247
08/01/2023, 3:42 PMproductOptions
. This will store the dynamic list of product choices.
2. Fetching Products: Next, add an Execute Code card to your workflow with the JS code:
js
try {
const listOfProducts = await ProductsTable.findRecords({
filter: AI`${userQuery}`
});
// Make sure to make the columns with relevant data Searchable
// If the data is in an object format, convert it using: const listOfProducts = Object.keys(yourObjectVariable)
// The listOfProducts variable needs to be an array of strings or objects
// Map the list to the format accepted by the Capture card
workflow.productOptions = listOfProducts.map((product) => {
return { label: product.Name, value: product.id };
});
} catch (error) {
console.log('Something went wrong: ', error);
}
This code retrieves a product list from a Table and formats the options for display. Customize it as per your needs.
3. Selecting a Product: Create a variable named selectedProductId
. Its data type should correspond to the value format of your product options (string or number).
4. Setting up the Choice Card: Create a Single Choice card:
- Store the result in selectedProductId
.
- Navigate to Choices > Items and select @productOptions
by clicking the {x} button .
5. Using the Selection: Finally, use the selectedProductId
variable according to your workflow's needs. This could be in another Execute Code card to fetch detailed information about the selected product, or within expressions to determine if a specific product has been chosen or if some property matches.
Adjust and expand upon this code to fit your unique application and workflow requirements. Happy building!early-train-33247
08/01/2023, 3:43 PMjs
{
name: "Talking robot toy",
id: "12345",
otherInfo: "any"
}
Add to the label property, the name you want to be displayed, and to the value property, the information that's unique for each product.
If you have a list of strings (text), you should use { label: product, value: product }
insteadearly-train-33247
08/01/2023, 3:46 PMcold-jewelry-54343
08/02/2023, 7:07 PMgentle-ability-75784
08/08/2023, 12:11 PMearly-train-33247
08/08/2023, 3:01 PMcold-jewelry-54343
08/08/2023, 3:11 PMhallowed-football-1829
08/11/2023, 1:05 PMearly-train-33247
08/18/2023, 2:00 AMearly-train-33247
09/05/2023, 8:28 PMearly-train-33247
09/05/2023, 8:30 PMbest-army-74344
01/15/2024, 8:25 PMbest-army-74344
02/27/2024, 7:29 PMearly-train-33247
02/28/2024, 5:39 PMcold-jewelry-54343
03/05/2024, 12:47 PMjs
try {
const listOfProducts = await Data2Table.findRecords({
filter: AI`${workflow.selectedProductId}`
});
// Make sure to make the columns with relevant data Searchable
// If the data is in an object format, convert it using: const listOfProducts = Object.keys(yourObjectVariable)
// The listOfProducts variable needs to be an array of strings or objects
// Map the list to the format accepted by the Capture card
workflow.productOptions = listOfProducts.map((product) => {
return { label: product.Name, value: product.Manufacturer, price: product.Price };
});
} catch (error) {
console.log('Something went wrong: ', error);
}
early-train-33247
03/05/2024, 12:51 PMjs
AI`Id is ${workflow.selectedProductId}`
early-train-33247
03/05/2024, 12:51 PMearly-train-33247
03/05/2024, 12:52 PMjs
filter: {
id: workflow.selectedProductId
}
Since it's an exact queryearly-train-33247
03/05/2024, 12:54 PMcold-jewelry-54343
03/05/2024, 3:08 PMjs
try {
const listOfProducts = await Data2Table.findRecords({
filter: AI`Find records with where the Name matches: ${workflow.lookup}`
});
workflow.productOptions = listOfProducts.map((product) => {
return {
label: product.Name,
value: product.Manufacturer,
carbrand: product.CarBrand,
price: product.Price,
stock: product.Stock
};
});
} catch (error) {
console.log('Something went wrong: ', error);
}
cold-jewelry-54343
03/05/2024, 3:13 PMid
(or in my case Name
) . This is quite important to figure out so any tips are appreciated.early-train-33247
03/05/2024, 5:53 PMjs
// Create the carousel items
const carouselItems = products.map((product, index) => {
const cardText = `${product.Name}\nThe price is ${product.Price}`
// the /n breaks a line
return {
type: 'card',
title: {
dynamicValue: cardText ,
valueType: 'dynamic'
},
imageUrl: {
dynamicValue: `${product.ImageSrc}`,
valueType: 'dynamic'
},
actions: [
{
action: 'postback',
label: {
dynamicValue: 'Open',
valueType: 'dynamic'
},
value: {
dynamicValue: `open_product_${product.id}`,
valueType: 'dynamic'
}
}
]
}
})
// Send the carousel
bp.dm.replyToEvent(event, {
type: 'carousel',
items: carouselItems
})
early-train-33247
03/05/2024, 5:54 PMfilter: AI`Name or description is like ${workflow.lookup}`
Remember to make the columns searchableearly-train-33247
03/05/2024, 5:54 PMearly-train-33247
03/05/2024, 5:56 PMopen_product_44
, to get the numeric product id use: const id = Number(event.preview.split("_")[2])
early-train-33247
03/05/2024, 5:58 PMcold-jewelry-54343
03/05/2024, 8:50 PMearly-train-33247
03/05/2024, 8:54 PMearly-train-33247
03/05/2024, 9:02 PMopen_product_23
, it has the same effect as clickingbest-army-74344
03/07/2024, 4:27 AMearly-optician-14851
04/04/2024, 5:15 AMearly-train-33247
04/04/2024, 1:31 PMbrave-bird-91413
04/04/2024, 5:43 PMearly-train-33247
04/04/2024, 6:15 PMbrave-bird-91413
04/04/2024, 6:41 PMearly-optician-14851
04/04/2024, 7:40 PMearly-optician-14851
04/04/2024, 7:41 PMtry {
const listOfProducts = await ProductsTable.findRecords({
filter: {
id: 1
}
})
// Make sure to make the columns with relevant data Searchable
// If the data is in an object format, convert it using: const listOfProducts = Object.keys(yourObjectVariable)
// The listOfProducts variable needs to be an array of strings or objects
// Map the list to the format accepted by the Capture card
workflow.productOptions = listOfProducts.map((product) => {
return { label: product.Name, value: product.id }
})
} catch (error) {
console.log('Something went wrong: ', error)
}
early-optician-14851
04/04/2024, 7:43 PM// Create the carousel items
const carouselItems = workflow.productOptions.map((product, index) => {
const cardText = `${product.label}`
return {
type: 'card',
title: {
dynamicValue: cardText,
valueType: 'dynamic'
},
imageUrl: {
dynamicValue: '',
valueType: 'dynamic'
},
actions: [
{
action: 'postback',
label: {
dynamicValue: 'Open',
valueType: 'dynamic'
},
value: {
dynamicValue: `open_product_${product.value}`,
valueType: 'dynamic'
}
}
]
}
})
// Send the carousel
bp.dm.replyToEvent(event, {
type: 'carousel',
items: carouselItems
})
early-train-33247
04/05/2024, 1:52 AMearly-train-33247
04/05/2024, 1:53 AMevent.preview = event.payload.text || event.payload.payload || event.payload.value || event.preview
early-train-33247
04/05/2024, 1:53 AMbrave-bird-91413
04/05/2024, 5:44 AMearly-optician-14851
04/05/2024, 6:56 AMearly-train-33247
04/05/2024, 6:40 PMearly-train-33247
04/05/2024, 6:41 PMp:
, in order to remove it and get the actual value, do something like this:early-train-33247
04/05/2024, 6:42 PMjs
let userSelection = event.payload.text || event.payload.payload || event.payload.value || event.preview || ''
if(userSelection.startsWith('p:')){
userSelection = userSelection.split('p:')[1]
}
event.preview = userSelection
best-army-74344
04/08/2024, 5:33 PMbest-army-74344
04/08/2024, 5:33 PMrapid-zoo-96848
04/11/2024, 6:24 AMcold-jewelry-54343
04/11/2024, 9:49 AMearly-train-33247
04/12/2024, 1:11 AMlimited-pencil-78283
04/19/2024, 8:14 AMSelect ${product.prd_name}
,
payload: product.prd_sku
}
]
}
})`
here is the log from carouselItems
info
card:Display products as a carousel card for user selection.
action
{ title: 'Nandini',
subtitle: 'Nandini Blue',
image: { url: 'https://versal.one/cdn/tic/milk/Nandini.png' },
actions:
[ { type: 'postback',
label: 'Select Nandini Blue',
payload: 'nandini_blue' } ] }, { title: 'Nandini',
subtitle: 'Nandini Gold',
image: { url: 'https://versal.one/cdn/tic/milk/Nandini-Gold.png' },
actions:
[ { type: 'postback',
label: 'Select Nandini Gold',
payload: 'nandini_gold' } ] }, { title: 'Heritage',
subtitle: 'Nandini Daily',
image: { url: 'https://versal.one/cdn/tic/milk/heritage-daily.jpg' },
actions:
[ { type: 'postback',
label: 'Select Nandini Daily',
payload: 'heritage-green' } ] }
but images are not shownlimited-pencil-78283
04/19/2024, 8:19 AMlimited-pencil-78283
04/19/2024, 8:20 AMcold-jewelry-54343
04/19/2024, 12:45 PMjs
image: {
url: product.image_link
},
Can you try :
js
image: {
url: `${product.image_link}`
},
fresh-fireman-491
04/19/2024, 1:46 PMlimited-pencil-78283
04/19/2024, 3:31 PMearly-train-33247
04/19/2024, 9:09 PMworried-artist-99581
04/20/2024, 9:30 AMcold-jewelry-54343
04/20/2024, 10:12 AMworried-artist-99581
04/20/2024, 11:35 AMcold-jewelry-54343
04/20/2024, 12:06 PMearly-train-33247
04/20/2024, 3:05 PMearly-train-33247
04/20/2024, 3:06 PMworried-artist-99581
04/21/2024, 4:28 AMlimited-pencil-78283
04/21/2024, 5:21 PMcold-jewelry-54343
04/21/2024, 8:01 PMhundreds-battery-97158
05/16/2024, 9:31 AMbrave-bird-91413
05/31/2024, 7:19 AMstocky-planet-21946
05/31/2024, 11:18 AMbest-army-74344
05/31/2024, 2:50 PMbest-army-74344
05/31/2024, 2:50 PMacceptable-smartphone-22753
06/01/2024, 5:05 PMfierce-zebra-31242
06/02/2024, 6:31 AMstale-table-60474
06/04/2024, 11:01 AMcold-jewelry-54343
06/04/2024, 1:20 PMwooden-beard-40210
06/08/2024, 3:50 PMbored-hamburger-45499
06/09/2024, 5:41 PMhallowed-hospital-35783
06/13/2024, 4:14 AMhallowed-hospital-35783
06/13/2024, 4:14 AMearly-shoe-82728
07/03/2024, 3:41 PMimportant-dinner-21198
07/31/2024, 9:36 PMif (workflow.productOptions && workflow.productOptions.length > 0) {
function createCardForProduct(product, index) {
// return {
// type: 'card',
// title: {
// dynamicValue: `${product.productName}`,
// valueType: 'dynamic'
// },
// image: {
// dynamicValue: `${product.productImageUrl}`,
// valueType: 'dynamic'
// },
// buttons: [
// {
// action: 'url',
// label: {
// dynamicValue: 'Open',
// valueType: 'dynamic'
// },
// value: {
// dynamicValue: `${product.productUrl}`,
// valueType: 'dynamic'
// }
// }
// ]
// Add other card properties like subtitle, actions
// ...
// }
return {
title: `${product.productName}`,
image: `${product.productImageUrl}`,
buttons: [
{
type: 'web_url',
title: 'Open',
url: `${product.productUrl}`
}
]
};
}
const carouselItems = workflow.productOptions.map((product, index) => createCardForProduct(product, index))
workflow.productOptions = [];
bp.dm.replyToEvent(event, {
type: 'carousel',
items: carouselItems
})
}
cold-jewelry-54343
08/30/2024, 7:34 AMclean-queen-65526
10/17/2024, 1:54 PMacceptable-lawyer-91415
01/04/2025, 1:51 PMacceptable-lawyer-91415
01/04/2025, 1:53 PMclever-exabyte-40857
02/08/2025, 6:16 PMpropertyId
. Once this button is clicked, I want to set a user.propertyId = button's bound property id.
2) I want to display a hyperlink next to "Book Now" that should open link in a new browser window.
How to do these two?white-nest-40686
02/08/2025, 7:45 PMtypescript
actions: [
{
action: 'postback',
label: 'Book Now',
value: `BOOKING_${product.propertyId}`
},
{
action: 'url',
label: 'View Property',
value: 'https://your.domain.site'
}
]
EDITED: i wrote type
instead of action
clever-exabyte-40857
02/09/2025, 10:15 AMwhite-nest-40686
02/09/2025, 10:39 AMwhite-nest-40686
02/09/2025, 1:42 PMts
/* example data to populate carousel */
const products = [
{
prd_sku: 'sku 1',
prd_brand: 'brand 1',
prd_name: 'product 1',
image_link: 'https://placehold.co/300x200?text=image+1&font=roboto'
},
{
prd_sku: 'sku 2',
prd_brand: 'brand 2',
prd_name: 'product 2',
image_link: 'https://placehold.co/300x200?text=image+2&font=roboto'
}
]
/* Create carousel */
const carouselItems = products.map((product) => {
return {
title: product.prd_brand,
subtitle: product.prd_name,
imageUrl: product.image_link,
actions: [
{
action: 'postback',
label: 'Buy Now',
value: `BOOKING_${product.prd_sku}`
},
{
action: 'url',
label: 'View Details',
value: 'https://www.botpress.com'
}
]
}
})
/* Show carousel */
bp.dm.replyToEvent(event, {
type: 'carousel',
items: carouselItems
})
red-nightfall-28336
03/02/2025, 11:30 AMwhite-nest-40686
03/02/2025, 11:38 AMred-nightfall-28336
03/03/2025, 7:26 AM