Rails App 中的 Javascript 在标头中有效,但在 js 文件中无效
问题:
我尝试编写一个简单的 javascript,如果单选按钮标记为“是”,则显示
<div>
,如果单选按钮标记为“否”,则隐藏。当我将 javascript 放在我的应用程序模板
<head>
文件中时,该 javascript 可以正常工作,但当我将其放在外部 .js 文件中时,该 javascript 则无法正常工作。我检查了编译后的 application.js,代码也显示了出来,所以我知道我的外部 .js 正在资源管道中加载。
错误消息
我在控制台中加载窗口时收到的错误是:
Uncaught TypeError: Cannot read property 'checked' of null
at locationPicked (intake.js:3)
at Object../app/javascript/custom/intake.js (intake.js:1)
at __webpack_require__ (bootstrap:19)
at Module.<anonymous> (application.js:18)
at Module../app/javascript/packs/application.js (application.js:18)
at __webpack_require__ (bootstrap:19)
at bootstrap:83
at bootstrap:83
单击“是”按钮时收到的错误是:
Uncaught ReferenceError: locationPicked is not defined
at HTMLInputElement.onclick
代码
以下是 Gemfile 中的 ruby​​ 和主要 gem 的版本:
ruby '2.6.2'
gem 'rails', '~> 6.0.2.2'
gem 'pg', '>= 1.1.4', '< 2.0'
gem 'puma', '~> 4.2.1'
gem 'sass-rails', '~> 6.0.0'
gem 'webpacker', '~> 4.0.7'
gem 'uglifier', '>= 4.2.0'
gem 'coffee-rails', '~> 5.0'
gem 'turbolinks', '~> 5.2.1'
gem 'jbuilder', '~> 2.9.1'
gem 'bootsnap', '>= 1.4.5', require: false
以下是单选按钮的 HTML 和 Ruby:
# app/views/events/intake.html.erb
<h2 style="text-decoration:underline; padding: 50px 0 25px 0;">Step 2 - Location</h2>
<div style="font-size: 1.5rem; padding: 0 0 15px 0;">
Location Picked:
<%= f.radio_button :location_picked, 'yes', onClick: "locationPicked()" %>
<%= label :location_picked_yes, 'Yes' %>
<%= f.radio_button :location_picked, 'no', onClick: "locationPicked()" %>
<%= label :location_picked_no, 'No' %>
</div>
<div class="row" id="LocationSelection" style="display:none">
<div class="col-5">
<div class="card bg-light">
<div class="card-header text-center"><h4>Select a Location</h4></div>
<div class="card-body">
<h5 class="card-title"><%= f.label :location_id, for: "location_id" %></h5>
<%= f.select :location_id, options_for_select(@locations, :selected => @selected_loc),{class: "custom-select"}, id:"location_id", class: "custom-select" %>
</div>
</div>
</div>
<div class="col-1">
<h4 class="text-center">OR</h4>
</div>
<div class="col-6">
<div class="card bg-light">
<div class="card-header text-center"><h4>Create a new Location</h4></div>
<div class="card-body">
<h5 class="card-title">Location Name</h5>
<%= f.text_field :location_name, class: "form-control", type:"text", id:"org_name" %>
</div>
</div>
</div>
</div>
浏览器看到的最终 HTML 是:
// Browser --> View Source
<h2 style="text-decoration:underline; padding: 50px 0 25px 0;">Step 2 - Location</h2>
<div style="font-size: 1.5rem; padding: 0 0 15px 0;">
Location Picked:
<input onClick="locationPicked()" type="radio" value="yes" name="event[location_picked]" id="event_location_picked_yes" />
<label for="location_picked_yes_Yes">Yes</label>
<input onClick="locationPicked()" type="radio" value="no" name="event[location_picked]" id="event_location_picked_no" />
<label for="location_picked_no_No">No</label>
</div>
<div class="row" id="LocationSelection" style="display:none">
<div class="col-5">
<div class="card bg-light">
<div class="card-header text-center"><h4>Select a Location</h4></div>
<div class="card-body">
<h5 class="card-title"><label for="location_id">Location</label></h5>
<select id="location_id" class="custom-select" name="event[location_id]"><option value="4">Helping Hands - Warehouse</option>
<option value="3">New City Church - College Room</option>
<option value="1">Samaritan Bags - Place Holder</option></select>
</div>
</div>
</div>
<div class="col-1">
<h4 class="text-center">OR</h4>
</div>
<div class="col-6">
<div class="card bg-light">
<div class="card-header text-center"><h4>Create a new Location</h4></div>
<div class="card-body">
<h5 class="card-title">Location Name</h5>
<input class="form-control" type="text" id="org_name" name="event[location_name]" />
</div>
</div>
</div>
</div>
以下是 javascript文件:
// app/javascript/custom/intake.js
window.onload = locationPicked();
function locationPicked() {
if (document.getElementById("event_location_picked_yes").checked) {
document.getElementById("LocationSelection").style.display = "block";
}
else document.getElementById("LocationSelection").style.display = "none";
}
这是我的 application.js:
// app/javascript/packs/application.js
require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
require('jquery')
import '../stylesheets/application'
import 'bootstrap'
document.addEventListener("turbolinks:load", () => {
$('[data-toggle="tooltip"]').tooltip()
$('[data-toggle="popover"]').popover()
})
// Custom Scripts
require("custom/global")
require("custom/intake")
当以上面列出的方式加载 javascript 时,会发生错误。当我在应用程序模板
<head>
部分中使用这样的 javascript 时,它可以工作:
// app/views/layouts/application.html.erb
<script type="text/javascript">
function locationPicked() {
if (document.getElementById("event_location_picked_yes").checked) {
document.getElementById("LocationSelection").style.display = "";
}
else document.getElementById("LocationSelection").style.display = "none";
}
</script>
问题
我的 javascript 很生疏。任何帮助都将不胜感激。我是否没有正确调用该函数?我想可能是打字错误,但代码在
<head>
部分有效,所以我想我排除了这一点。提前感谢您的帮助。
尝试此代码并从 app/views/layouts/application.html.erb 中删除脚本
app/javascript/custom/intake.js
$(document).on('turbolinks:load', function() {
function locationPicked() {
if (document.getElementById("event_location_picked_yes").checked) {
document.getElementById("LocationSelection").style.display = "block";
}
else document.getElementById("LocationSelection").style.display = "none";
}
});
我读了这篇文章,因为我遇到了类似的问题。在写信询问您是否找到了解决方案 15 分钟后(经过几个小时的尝试),我找到了答案;您需要删除
()
,即
window.onload = locationPicked;
我的 JS 也不太好,但在我的例子中,找不到
document.getElementById...
。我从您那里得到了线索,您说代码在包含在 html.erb 页面上时有效。我也是,我记得我之前用过这个问题
window.onload = init;
function init() {
<JavaScript code which works on html.erb>
}
在重写这篇文章时,我去这里找到了解释: window.onload = init() 之间有什么区别;和 window.onload = init; 。
该线程 (@Ernest Friedman-Hill) 中最简单的解释是:“
没有括号的那个在窗口加载时运行该函数。带括号的那个在分配完成时运行该函数,例如可能在评估页面的 HEAD 时
,”(搜索很容易,因为
window.onload = init
很常见,并且解释了发生了什么。)但我知道我需要等到页面加载后才能运行脚本吗?不知道!
作为最后的测试,我在代码的第一行添加了
()
,页面无法完全加载,但没有控制台错误。我现在知道这是因为代码意味着不同的东西。JS 的乐趣!