如何在Apostrophe的trainings-forms中从谷歌日历填充日期字段?
解决Apostrophe表单日期字段从谷歌日历动态填充的问题
我之前在Apostrophe CMS里处理过类似的动态表单字段需求,给你一步步拆解怎么实现:
第一步:在pageBeforeSend中获取并传递日历数据
你已经在trainings-forms-submit-widgets的pageBeforeSend里写了获取谷歌日历数据的代码,接下来要把这些数据绑定到对应的trainings-forms widget上。Apostrophe提供了self.apos.util.walk工具方法,可以遍历页面中的所有widget,找到目标表单后挂载数据:
module.exports = { construct: function(self, options) { self.pageBeforeSend = async function(req) { // --- 这里放你获取谷歌日历数据的异步代码 --- const { google } = require('googleapis'); const calendar = google.calendar({ version: 'v3', auth: '你的授权凭证' }); const calendarResponse = await calendar.events.list({ calendarId: '你的谷歌日历ID', timeMin: new Date().toISOString(), maxResults: 10, singleEvents: true, orderBy: 'startTime', }); // 提取出需要的日期格式,比如转为YYYY-MM-DD或者带时间的格式 const availableDates = calendarResponse.data.items.map(event => { return event.start.dateTime || event.start.date; }); // --- 找到trainings-forms widget并传递数据 --- if (req.data.page) { // 遍历页面所有widget,定位到trainings-forms类型的表单 self.apos.util.walk(req.data.page, (widget) => { if (widget.type === 'trainings-forms') { // 把日历数据挂载到widget的自定义属性上,模板里就能直接用 widget.availableTrainingDates = availableDates; } }); } }; } };
第二步:在表单模板中渲染填充数据
接下来修改trainings-forms widget的模板文件(路径一般是lib/modules/trainings-forms/views/widget.html),根据你的日期字段类型(下拉框/输入框)来渲染数据:
示例1:下拉选择框
<div class="form-group"> <label for="training-date">选择培训日期</label> <select id="training-date" name="training-date" required> {% for date in widget.availableTrainingDates %} <option value="{{ date }}">{{ date | date('YYYY-MM-DD HH:mm') }}</option> {% endfor %} </select> </div>
示例2:日期输入框(默认填充第一个可用日期)
<div class="form-group"> <label for="training-date">培训日期</label> <input type="datetime-local" id="training-date" name="training-date" value="{{ widget.availableTrainingDates[0] | date('YYYY-MM-DDTHH:mm') }}" required > </div>
关键注意点
- 因为谷歌日历API调用是异步操作,一定要用
async/await包裹,确保数据获取完成后再传递给widget,避免出现空数据的情况。 self.apos.util.walk会遍历页面中所有区域(areas)里的widget,不管表单放在哪个区域都能定位到。- 如果你的表单有多个实例,这个方法会给所有
trainings-formswidget都填充数据,要是需要针对特定实例,可以给widget加个自定义属性(比如widget.slug)来筛选。
内容的提问来源于stack exchange,提问作者Michał Sadowski
相关产品推荐
相关产品推荐

