Laravel Blade表单JS验证报Cannot read properties of null错误
问题描述
在Laravel Blade模板中开发表单功能,使用JavaScript实现前端表单校验时,控制台抛出异常:Uncaught TypeError: Cannot read properties of null (reading 'addEventListener')
相同校验逻辑在其他页面可正常运行,无法定位当前页面报错原因。
涉及的表单代码如下:
<form action="#" method = "POST"> @csrf <div class="form-row"> <div class="form-group col-lg-6 col-md-12 col-sm-12 col-12"> <label for="first_name">First Name</label> <input type="text" id="fname" name = "first_name" class="form-control" placeholder="First Name" > <div id="namevalid" class="form-text text-muted invalid-feedback"> Your name should be 3-15 characters long and shouldn't contain a number </div> </div> <div class="form-group col-lg-6 col-md-12 col-sm-12 col-12"> <label for="last_name">Last Name</label> <input type="text" name = "last_name" class="form-control" placeholder="Last Name" required pattern="[a-zA-Z]([0-9a-zA-Z]){4,30}" min="4" max="30" title="Min 4 Max 30 Chars No Spaces No Special Charachters"> </div> <div class="form-group col-lg-6 col-md-12 col-sm-12 col-12"> <label for="subject">Subject</label> <input type="text" name = "subject" class="form-control" placeholder="Subject" required pattern = '[a-zA-Z]([0-9a-zA-Z]){4,50}' min="5" max="50" title="Max Length exceeded of 50 chars and Single Word Subject e.g wedding"> </div> </div> <label for="email">Email</label> <input type="text" name ="email" class="form-control" placeholder="Email" required pattern="([a-zA-Z0-9_\-.]+)@([a-zA-Z0-9_\-.]+)\.([a-zA-Z]){2,7}" title="Only . allowed no Spaces no special characters"> <label for="message">Your Message</label> <textarea name ="message" class="form-control mb-3" placeholder="Type Here" id="" cols="10" rows="5" required min="5" max ="5000" title="Message cannot be empty"></textarea> <button type = "submit" class="btn btn-success float-right">Send Message</button> </form>
涉及的JavaScript校验代码如下:
const fname= document.getElementById('fname'); console.log(fname) fname.addEventListener('blur', ()=>{ console.log("first name is blurred"); // First name Validation let regex = /^[a-zA-Z]$/; let str = fname.value; console.log(regex, str); if(regex.test(str)){ console.log('First name is valid'); fname.classList.remove('is-invalid'); } else{ console.log('Last name is not valid'); fname.classList.add('is-invalid'); } })
报错根因
错误触发逻辑非常明确:执行document.getElementById('fname')时返回值为null,也就是JS代码运行的时机,页面DOM树里还不存在id为fname的输入框元素,对null值调用addEventListener方法就会抛出类型错误。
相同逻辑在其他页面能正常运行,核心原因是其他页面的JS代码要么放在了对应DOM元素的后方(浏览器解析到JS时已经完成前面DOM的渲染,能正常拿到元素),要么加了DOM加载完成的监听事件。当前页面的JS代码大概率放在了表单DOM的前面(比如head标签里、body最开头),浏览器从上到下解析页面时先运行了JS,此时下方的表单元素还没被解析加载,自然拿不到对应节点。
另外现有代码还有两处逻辑问题:
- 校验正则
/^[a-zA-Z]$/只能匹配单个英文字母,和提示文案里「3-15个字符、不能包含数字」的规则不匹配 - 校验失败时的日志打印错误,把First name写成了Last name
修复方案
任选以下一种方案即可解决报错:
- 方案1:把JS代码移动到
</body>标签之前,也就是所有页面DOM元素的最后方,保证JS运行时所有DOM已经解析完成。 - 方案2:给JS代码加上DOM加载完成的监听,等整个DOM树解析完毕再执行元素获取和事件绑定逻辑,修正后的JS代码如下:
// DOM全部加载完成后再执行绑定逻辑 document.addEventListener('DOMContentLoaded', function() { const fname= document.getElementById('fname'); console.log(fname) fname.addEventListener('blur', ()=>{ console.log("first name is blurred"); // 修正正则,匹配3-15位纯英文字母,自动去除首尾空格 let regex = /^[a-zA-Z]{3,15}$/; let str = fname.value.trim(); console.log(regex, str); if(regex.test(str)){ console.log('First name is valid'); fname.classList.remove('is-invalid'); } else{ console.log('First name is not valid'); fname.classList.add('is-invalid'); } }) })
- 额外排查点:如果用了Laravel的布局继承、组件语法,要确认当前页面没有出现id重复的情况,或者
fname输入框被@if等条件语法包裹导致没有实际渲染到页面上,从贴出的代码判断这个概率极低,99%的场景都是JS加载时机错误导致的问题。
内容的提问来源于stack exchange,提问作者Faaiz Aslam
相关产品推荐
相关产品推荐

