开发者问题收集

Rails App 中的 Javascript 在标头中有效,但在 js 文件中无效

2020-09-25
383

问题:

我尝试编写一个简单的 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> 部分有效,所以我想我排除了这一点。提前感谢您的帮助。

2个回答

尝试此代码并从 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";
  }
});
rock
2020-09-25

我读了这篇文章,因为我遇到了类似的问题。在写信询问您是否找到了解决方案 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 的乐趣!

Greg
2020-12-01