为什么这个 JS 会在 1 页上部分呈现的表单上触发,而不是在另一个页面上触发
Why would this JS fire on a form partial rendered on 1 page but not another?
我有一个看起来像这样的posts.js
文件:
var ready;
ready = function() {
var toggleSidebar = $(".togglesidebar");
var primary = $("#primary");
var secondary = $("#secondary");
toggleSidebar.on("click", function(){
if(primary.hasClass("col-sm-9")){
primary.removeClass("col-sm-9");
primary.addClass("col-sm-12");
secondary.css('display', 'none');
}
else {
primary.removeClass("col-sm-12");
primary.addClass("col-sm-9");
secondary.css('display', 'inline-block');
}
});
};
var counter = function(event) {
var fieldValue = $(this).val();
var wc = fieldValue.trim().replace(regex, ' ').split(' ').length;
var regex = /'s+/gi;
var $wcField;
var maxWc;
if ($(this)[0] === $('#post_title')[0]) {
$wcField = $('#wordCountTitle');
maxWc = 7;
} else {
$wcField = $('#wordCountBody');
maxWc = 150;
}
$wcField.html(wc);
$wcField.toggleClass('over-limit', wc > maxWc);
};
$(document).ready(ready);
$(document).on('ready page:load', function () {
$('#post_title, #body-field').on('change keyup paste', counter);
});
在我的application.html.erb
页面中,我有这个:
<div id="secondary" class="col-sm-3 sidebar" style="display: none;">
<aside>
<div class="about">
<h4>Submit Report</h4>
<%= render "posts/form" %>
</div>
</aside>
</div> <!-- /#secondary -->
当我切换这个div并显示_form
部分时,JS在这些字段中工作正常。
但是如果我去posts/new
或/posts/:id/edit
,它不会。
即使我检查该页面的来源,我也会看到其中包含post.js
。
可能是什么原因造成的?
编辑 1
我正在使用涡轮链接,如果这很重要的话。
编辑 2
根据答案中的建议,我尝试了这个:
var ready;
ready = function() {
// This is the Sidebar toggle functionality
var toggleSidebar = $(".togglesidebar");
var primary = $("#primary");
var secondary = $("#secondary");
$(document).on("click", ".togglesidebar", function(){
if(primary.hasClass("col-sm-9")){
primary.removeClass("col-sm-9");
primary.addClass("col-sm-12");
secondary.css('display', 'none');
}
else {
primary.removeClass("col-sm-12");
primary.addClass("col-sm-9");
secondary.css('display', 'inline-block');
}
});
};
但这并没有奏效。
我遇到问题的关键问题是"计数器",即 #wordCountTitle
和#wordCountBody
不适用于我的/posts/new
,即使它们在激活.toggleSidebar
时在posts/index
上工作。
与其直接绑定到需要仔细处理 Turbolinks 事件的元素的 onclick,不如在文档上使用事件处理程序,尝试更改直接事件
toggleSidebar.on("click", function(){
到委托事件
$(document).on("click", ".togglesidebar", function(){
当您动态修改 DOM 时(就像 Turbolinks 替换它时一样(,如果您使用直接事件,则需要重新分配它。
有关详细说明,请参阅 http://api.jquery.com/on/#direct-and-delegated-events
第一个函数也是如此,代表第二个函数。此外,对于委托事件,"就绪"检查变得没有必要。考虑到这一点,您的代码将变为:
$(document).on("click", ".togglesidebar", function(){
var primary = $("#primary");
var secondary = $("#secondary");
if(primary.hasClass("col-sm-9")){
primary.removeClass("col-sm-9");
primary.addClass("col-sm-12");
secondary.css('display', 'none');
}
else {
primary.removeClass("col-sm-12");
primary.addClass("col-sm-9");
secondary.css('display', 'inline-block');
}
});
$(document).on('change keyup paste', '#post_title, #body-field', function () {
var fieldValue = $(this).val();
var wc = fieldValue.trim().replace(regex, ' ').split(' ').length;
var regex = /'s+/gi;
var $wcField;
var maxWc;
if ($(this)[0] === $('#post_title')[0]) {
$wcField = $('#wordCountTitle');
maxWc = 7;
} else {
$wcField = $('#wordCountBody');
maxWc = 150;
}
$wcField.html(wc);
$wcField.toggleClass('over-limit', wc > maxWc);
});
我在我的一个项目中使用了这样的东西,有同样的问题希望它有帮助:
window.onLoad = function(callback) {
$(document).ready(callback);
$(document).on('page:load', callback);
};
然后用onLoad包装我的函数,类似于
onLoad(function() {
counter()
});
onLoad 函数绑定就绪事件和涡轮链接页面:加载事件
当你这样做时
$("selector").on("click", function(){});
您实际上将选择器绑定到 Click 事件。
白色(如果使用(
$(document).on("click", "selector", function(){});
将 click 事件绑定到文档,该文档在单击后检查单击的元素是否是您使用的选择器。 如果是,则执行函数。因此,每当在动态元素上绑定事件时,都应使用第二种方法。
我希望这回答了"为什么"的问题
很长一段时间我不使用 jQuery,但自从我来到这里:如果你有多个带有选择器".sidebar"的元素,我相信你需要使用".each"将函数绑定到与 dom 上的选择器匹配的所有元素。
有关参考,请转到此处 http://api.jquery.com/each/
希望这有帮助,祝你好运。
我看了一下Turbolinks,它做了我认为的那样:它将链接的HTML内容加载到主页上的容器内。问题是,它加载的任何内容都与您在主页加载时声明的任何事件和函数无关,因此,实际上,在第一次单击之后,它刚刚加载的 HTML 上的选择器不会将点击事件归因于它(当您进行绑定时它不在 DOM 上(。
可能的解决方案:我对 .live(( 方法做了一些研究,但已被弃用,所以我建议做这样的事情:
$('body'(.on('click','a.saveButton', saveHandler(
绑定到你需要的元素,似乎可以确保Turbolinks在体内加载的任何内容都会得到你声明的绑定。
这里有一个更详细的答案:Javascript事件绑定持久性
.live 钩子的文档在这里:http://api.jquery.com/live/#typefn
过去,我的网页上曾经有相同的架构,但我确实遇到了与您类似的问题。
希望对您有所帮助。
如果它有效.. 确保:
- 没有 id 冲突。
- 你的html结构,也许你忘记在你的帖子中放值。
- 也许错误的路径帖子.js,使用 CTRL+U 打开,然后单击发布.js显示您的代码的内容,如果有的话,没关系。
我试试这样,没关系(假人(:
$(document).on("click", ".togglesidebar", function(){
var primary = $("#primary");
var secondary = $("#secondary");
if(primary.hasClass("col-sm-9")){
primary.removeClass("col-sm-9");
primary.addClass("col-sm-12");
secondary.css('display', 'none');
}
else {
primary.removeClass("col-sm-12");
primary.addClass("col-sm-9");
secondary.css('display', 'inline-block');
}
});
$(document).on('change keyup paste', '#post_title, #body-field', function () {
var fieldValue = $(this).val();
var wc = fieldValue.trim().replace(regex, ' ').split(' ').length;
console.log(wc);
var regex = /'s+/gi;
var $wcField;
var maxWc;
if ($(this)[0] === $('#post_title')[0]) {
$wcField = $('#wordCountTitle');
maxWc = 7;
} else {
$wcField = $('#wordCountBody');
maxWc = 150;
}
$wcField.html(wc);
$wcField.toggleClass('over-limit', wc > maxWc);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="togglesidebar">Toogle</div>
<div id="wordCountTitle"></div>
<div id="wordCountBody"></div>
<div id="primary">
<div id="secondary" class="col-sm-3 sidebar" style="display: none;">
<aside>
<div class="about">
<h4>Submit Report</h4>
<input type="text" id="body-field"/>
</div>
</aside>
</div> <!-- /#secondary -->
</div>
高效工作的最佳方法是安装 jquery rails gem,添加//require jquery-Turbolinks,然后在 Js 文件中删除//require turbolinks
确保在 jQuery 选择器上传递的 id 是唯一的。如果加载该页面/部分页面而不进行回发,则应使用
//document or selector that does not get removed
var primary = $(document).find('#primary');
var secondary = $(document).find('#secondary');
这,与
$(document).click('eventName', 'contextSelector', function)
应该有助于解决问题。
如果#post_title
和#body-field
是动态创建的,则需要更改:
$('#post_title, #body-field').on('change keyup paste', counter);
对此:
$(document).on('change keyup paste', '#post_title, #body-field', counter);
当定位加载页面时不存在的元素(可能是#post_title
和#body-field
(时,您需要将事件委托给页面加载时存在的元素(在本例中为document
本身(。
关于/posts/new
上的$('#wordCountTitle')
和$('#wordCountBody')
,您是否尝试过在控制台上输入其中任何一个?/posts/new
的视图可能与您的索引不同,并且缺少这些 id(或者您将它们设置为类或发生了其他一些换位(。
我在Turbolinks和jquery上遇到了各种各样的问题,所以关于如何尝试解决您的问题的一些建议:
-
使用
gem 'turbolinks'
来包含它。按照说明进行操作,并以Ruby(gems(的方式而不是PHP的方式进行操作。 -
使用Turbolinks意味着
$(document).ready
不会在加载新的"页面"时触发。解决方案是使用:$(document).on('page:load', ready)
与$(document).ready(ready)
一起使用。page:load
事件是ready
事件的Turbolinks版本。 -
其他人建议这样做,但我发现它在我的rails应用程序中非常有价值:绑定到文档不是直接将事件绑定到选择器
$("a").click(/* function */)
,而是绑定到文档意味着当Turbolinks加载新页面时,文档绑定在页面加载中幸存下来:$(document).on('click', 'a.particularAnchor', particularAnchorClicked)
考虑到您的特定代码,我会更改以下内容:
$('#post_title, #body-field').on('change keyup paste', counter);
自
$(document).on('change keyup paste', '#post_title, #body-field', counter);
在我看来,在您的counter
函数中,您混合了以下两行(regex
需要先定义(
var wc = fieldValue.trim().replace(regex, ' ').split(' ').length;
var regex = /'s+/gi;
- 循环遍历包含另一个表单的表单
- 如何通过 JS 将内容从一个表单中的一个文本框复制到另一个表单中的另一个文本框
- 使用 javascript 将值从一个表单传递到另一个表单
- 如何将一个表单中的项目添加到 Rails 中另一个表单的下拉选项
- 在PHP中将下拉选择列表的内容从一个表单传递到另一个表单
- Javascript-更正用户名和密码以启用另一个表单
- angular js如何在提交一个表单时验证另一个表单
- 如何将某些HTML从一个页面转换为另一个表单
- 两个表单,一个选择/下拉框-需要将选择值从一个表单复制到另一个表单
- 将html输入文件元素从一个表单复制到另一个表单
- 使用javascript或jquery从另一个表单中使用它所在的URL访问,填写和提交表单
- 如何计算两个输入表单字段并将值放入另一个表单中,而无需使用 jquery 提交表单
- 使用来自另一个表单的数据填充表单
- HTML:如何使一个表单显示在另一个表单之上
- 通过get使用javascript或jquery将数据从一个表单推送到另一个表单
- document.getElementById 适用于一个表单元素,但不适用于另一个表单元素
- 在另一个表单中提交表单
- JQuery & HTML:如何使用echo $_POST将数据从一个表单获取到另一个表单
- 将选定表单的元素发送到另一个表单
- 使用链接自动填充另一个表单是可能的