Cannot read property 'templateId' of undefined 小程序无法读取模板id的原因

一、问题产生

小程序开发过程中,在使用小程序的模板下发功能时遇到这样一个问题:

核心错误在这句:"Cannot read property 'templateId' of undefined" 无法读取未定义的templateId。

我是将官方的小程序示例中模板消息下发模块的代码移植过来的,使用的是云调用中的模板消息下发,如图

Cannot read property 'templateId' of undefined 小程序无法读取模板id的原因_第1张图片

 

将代码移植过来,自己创建目录文件,其中只用到js文件和html文件

Cannot read property 'templateId' of undefined 小程序无法读取模板id的原因_第2张图片

修剪代码后的js代码

Page({
  sendTemplateMessageViaCloudFunction(e) {
    wx.cloud.callFunction({
      name: 'openapi',
      data: {
        formId: e.detail.formId,
      },
    }).then((res) => {
      console.log('[云调用] [发送模板消息] 成功: ', res)
    }).catch(err => {
      console.error('[云调用] [发送模板消息] 失败: ', err)
    })
  }
})

html代码

云函数目录

Cannot read property 'templateId' of undefined 小程序无法读取模板id的原因_第3张图片

修剪后的index.js代码

const cloud = require('wx-server-sdk')
cloud.init()

async function sendTemplateMessage(event) {
  const {
    OPENID
  } = cloud.getWXContext()


  // 接下来将新增模板、发送模板消息、然后删除模板
  // 注意:新增模板然后再删除并不是建议的做法,此处只是为了演示,模板 ID 应在添加后保存起来后续使用
  const addResult = await cloud.openapi.templateMessage.addTemplate({
    id: 'AT0002',
    keywordIdList: [3, 4, 5]
  })
  console.log(addResult)

  const templateId = addResult.result.templateId
  const sendResult = await cloud.openapi.templateMessage.send({
    touser: OPENID,
    templateId,
    formId: event.formId,
    page: 'source/pages/index/index',
    data: {
      keyword1: {
        value: '未名咖啡屋',
      },
      keyword2: {
        value: '2019 年 1 月 1 日',
      },
      keyword3: {
        value: '拿铁',
      }
    }
  })

  await cloud.openapi.templateMessage.deleteTemplate({
    templateId,
  })

  return sendResult

}

// 云函数入口函数
// eslint-disable-next-line
exports.main = async(event) => {

  return sendTemplateMessage(event)

}

 

二、问题分析

代码环境如上给出,接下来分析下产生这个问题的原因。

在云调用中首次出现templateId的地方是这一句:const templateId = addResult.result.templateId

这句的作用是将addResult的对象result的templateId值赋给templateId

我们很好奇明明有赋值,但是为什么提示未定义?

 

我们这样做:只简单的添加模板,不发送模板消息,修改云调用的代码如下:

const cloud = require('wx-server-sdk')
cloud.init()

async function sendTemplateMessage(event) {
  const {
    OPENID
  } = cloud.getWXContext()

  // 接下来将新增模板、发送模板消息、然后删除模板
  // 注意:新增模板然后再删除并不是建议的做法,此处只是为了演示,模板 ID 应在添加后保存起来后续使用
  const addResult = await cloud.openapi.templateMessage.addTemplate({
    id: 'AT0002',
    keywordIdList: [3, 4, 5]
  })

  return addResult
}

// 云函数入口函数
// eslint-disable-next-line
exports.main = async(event) => {

  return sendTemplateMessage(event)

}

运行后,控制台打印结果如下:

Cannot read property 'templateId' of undefined 小程序无法读取模板id的原因_第4张图片

注意看result的值,result为一个对象,它有三个属性,分别为errCode,errMsg,templateId。我们在只添加模板时成功返回了templateId,按理说 "const templateId = addResult.result.templateId" 这行代码应该不会有错的。

难道说result里没有templateId?(怎么诡异?!)

于是乎,我在云调用中了添加一句:console.log(addResult) 想查看一下这个值在云开发打印的日志中是个什么情况

云调用代码如下:

const cloud = require('wx-server-sdk')
cloud.init()

async function sendTemplateMessage(event) {
  const {
    OPENID
  } = cloud.getWXContext()

  // 接下来将新增模板、发送模板消息、然后删除模板
  // 注意:新增模板然后再删除并不是建议的做法,此处只是为了演示,模板 ID 应在添加后保存起来后续使用
  const addResult = await cloud.openapi.templateMessage.addTemplate({
    id: 'AT0002',
    keywordIdList: [3, 4, 5]
  })
  console.log(addResult)

  return addResult

}

// 云函数入口函数
// eslint-disable-next-line
exports.main = async(event) => {

  return sendTemplateMessage(event)

}

 

云开发后台日志打印结果:

本地控制台打印结果:

Cannot read property 'templateId' of undefined 小程序无法读取模板id的原因_第5张图片

我们发现云开发和本地的结果中templateId的所在位置不一样,云开发中templateId本身在"{}"中,本地的结果是templateId属于result的值。云开发中的打印结果是由console.log(addResult)打印的,本地的是由console.error('[云调用] [发送模板消息] 失败: ', err)打印的,而在云调用函数中templateId 是这样赋值的:const templateId = addResult.result.templateId

分析以上,就大概知道为什么了。

根据错误的提示 Cannot read property 'templateId' of undefined 无法读取templateId属性,以及云开发的打印结果

错误的原因很明显:

在本地打印的结果中templateId存在于result中,但是在云函数中templateId是在addResult中的

所以以下这个获取templateId的方式会报错:

const templateId = addResult.result.templateId

addResult根本没有result值,它的值是errCode,errMsg,templateId

三、问题解决

知道错误原因后,解决方法很简单。

只需修改这句代码:

const templateId = addResult.templateId

修改后通过云调用模板消息成功下发:

Cannot read property 'templateId' of undefined 小程序无法读取模板id的原因_第6张图片

 

问题解决后,有一个疑问是为什么在只添加模板时,云开发日志的打印结果和本地的打印结果templateId所在位置不一样?

原因是:

本地的 console.error('[云调用] [发送模板消息] 失败: ', err) 中的err携带的值不仅有云函数sendTemplateMessage的返回值addResult还有wx.cloud.callFunction函数调用后返回的信息,信息中说明了wx.cloud.callFunction函数是否调用成功。

还有一个疑问是,在小程序示例中云调用模板下发没有问题,移植代码却不行,这是为什么?修改那句却可以了。那官方的为什么就可以?只能说这个github下的小程序示例的源码比较诡异了...

你可能感兴趣的:(微信小程序)