Tacton CPQ is a powerful tool for managing complex product configurations, but sometimes a standard UI isn't enough. What if you need an advanced calculation tool or a customized data entry form?
Instead of manually building a static form, you can dynamically generate one based on parameters received from CPQ.
In this post, we’ll walk through how to create an external HTML form that dynamically adapts to the configuration, sends data to an external API, and commits results back to CPQ—all using window.postMessage
.
From a business perspective, a dynamically populated form offers:
For example, if a customer is configuring an industrial crane, the form might display weight limits and dimensions, but if they switch to an elevator system, it might show load capacity and motor specifications. With a dynamic form, these changes happen automatically.
To populate the form dynamically, we first need to listen for incoming data from CPQ:
function handlePostMessage(event) {
try {
const parsedData = JSON.parse(event.data);
if (parsedData.type === "parameters" && Array.isArray(parsedData.parameters)) {
parameters = parsedData.parameters.reduce((acc, param) => {
acc[param.name] = param.value;
return acc;
}, {});
generateForm(); // Create form dynamically
}
} catch (error) {
console.error("Invalid message format", error);
}
}
window.addEventListener("message", handlePostMessage, false);
What’s happening?
window.postMessage
.parameters
object.generateForm()
to dynamically create input fields based on the received parameters.
Once we have the parameters, we need to create corresponding input fields on the page.
function generateForm() {
const parametersContainer = document.getElementById("parametersContainer");
parametersContainer.innerHTML = ""; // Clear any previous inputs
for (const [key, value] of Object.entries(parameters)) {
const label = document.createElement("label");
label.textContent = key;
const input = document.createElement("input");
input.type = "text";
input.id = key;
input.value = value;
parametersContainer.appendChild(label);
parametersContainer.appendChild(input);
}
}
Key takeaways:
<input>
field with a corresponding label.
Once the user fills in the form, we need to send the updated values to an external service, such as a pricing or validation engine.
async function sendData() {
const requestBody = {};
Object.keys(parameters).forEach(key => {
requestBody[key] = document.getElementById(key).value;
});
const endpoint = "https://example.com/api"; // Replace with actual API URL
try {
const response = await fetch(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(requestBody)
});
const data = await response.json();
displayResponse(data);
} catch (error) {
console.error('Error:', error);
}
}
This step enables complex calculations to be performed outside of Tacton CPQ before committing the results back.
Once we receive a response from the external API, we need to return the data to CPQ and update the configuration.
function commitToCPQ() {
const payload = { fields: {} };
document.querySelectorAll("#responseContainer input").forEach(input => {
const key = input.id.replace("response_", "");
payload.fields[key] = input.value;
});
const message = {
namespace: "configuration_actions",
action: "commit",
payload: payload
};
window.top.postMessage(message, "*");
}
Final step: Clicking "Commit" sends the updated values back to CPQ.
By integrating an external, dynamically generated form with Tacton CPQ, businesses can achieve:
Whether you need a pricing calculator, a validation tool, or an advanced UI, this approach can significantly enhance the configurator experience.
Interested in learning more? Our CPQ experts can help you implement custom integrations for your business.