What I want to achieve is to create a dynamic dropdown (fetch from a database and based on the selection display a list of items).
The problem is I can't get the onChangeAction
to work this is on my home card so I configured the action to trigger the function of my home card.
{
widgets: [
{
selectionInput: {
type: 'DROPDOWN',
name: 'projects',
label: 'Select project',
items: projects.map((project) => ({
text: project.name,
value: project.id,
selected: project.id === selectedProjectId,
})),
onChangeAction: {
function:
'https://xxxxxxxx/onCalendarHomePageOpen',
parameters: [],
},
},
},
],
}
I see this error:
Cannot find field: action in message google.apps.card.v1.SubmitFormResponse
Then I add render_actions and the onChange works, but the rest state breaks.
This same thing happens when I try to navigate back to the home card from another one.
I just noticed you mention renderActions
in the common card ui generator, and then render_actions
in the card ui generators, I'm not sure about what's the difference.
Thank you very much
I found the answer here: https://codelabs.developers.google.com/codelabs/workspace-add-on-nodejs-cloudrun#5
You have to create a new endpoint, build the card and pass it to the updateCard method.
Fetch tasks
app.post('/', asyncHandler(async (req, res) => {
const event = req.body;
const user = await userInfo(event);
const tasks = await listTasks(user.sub);
const card = buildCard(req, tasks);
const responsePayload = {
action: {
navigations: [{
pushCard: card
}]
}
};
res.json(responsePayload);
}));
Add task
app.post('/newTask', asyncHandler(async (req, res) => {
const event = req.body;
const user = await userInfo(event);
const formInputs = event.commonEventObject.formInputs || {};
const newTask = formInputs.newTask;
if (!newTask || !newTask.stringInputs) {
return {};
}
const task = {
text: newTask.stringInputs.value[0],
created: new Date()
};
await addTask(user.sub, task);
const tasks = await listTasks(user.sub);
const card = buildCard(req, tasks);
const responsePayload = {
renderActions: {
action: {
navigations: [{
updateCard: card
}],
notification: {
text: 'Task added.'
},
}
}
};
res.json(responsePayload);
}));
buildCard method
function buildCard(req, tasks) {
const baseUrl = `${req.protocol}://${req.hostname}${req.baseUrl}`;
// Input for adding a new task
const inputSection = {
widgets: [
{
textInput: {
label: 'Task to add',
name: 'newTask',
value: '',
onChangeAction: {
function: `${baseUrl}/newTask`,
},
}
}
]
};
const taskListSection = {
header: 'Your tasks',
widgets: []
};
if (tasks && tasks.length) {
// Create text & checkbox for each task
tasks.forEach(task => taskListSection.widgets.push({
decoratedText: {
text: task.text,
wrapText: true,
switchControl: {
controlType: 'CHECKBOX',
name: 'completedTasks',
value: task[datastore.KEY].id,
selected: false,
onChangeAction: {
function: `${baseUrl}/complete`,
}
}
}
}));
} else {
// Placeholder for empty task list
taskListSection.widgets.push({
textParagraph: {
text: 'Your task list is empty.'
}
});
}
const card = {
sections: [
inputSection,
taskListSection,
]
}
return card;
}