为什么这个JS会在一页上部分呈现而不是另一页?

时间:2015-02-20 00:34:22

标签: javascript jquery ruby-on-rails ruby-on-rails-4 asset-pipeline

我有一个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 partial时,JS在这些字段中正常工作。

但如果我转到posts/new/posts/:id/edit,则不会。

即使我检查该页面的来源,我也会看到其中包含post.js

导致这种情况的原因是什么?

修改1

如果重要的话,我正在使用Turbolinks。

修改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上无效,即使它们在{{1}上工作当posts/index被激活时。

10 个答案:

答案 0 :(得分:7)

您可以在文档上使用事件处理程序,尝试更改直接事件

,而不是直接绑定到需要仔细处理Turbolinks事件的元素onclick上。
toggleSidebar.on("click", function(){

到委派活动

$(document).on("click", ".togglesidebar", function(){

当您动态修改DOM时(如Turbolinks替换它),如果您使用直接事件,则需要重新分配它。

有关详细说明,请参阅http://api.jquery.com/on/#direct-and-delegated-events


与第一个函数相同的代表第二个函数。此外,通过委派活动,&#34; ready&#34;检查变得不必要。考虑到这一点,您的代码将成为:

$(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);
});

答案 1 :(得分:1)

我在我的一个项目中使用这样的东西,有同样的问题希望它有所帮助:

window.onLoad = function(callback) {
  $(document).ready(callback);
  $(document).on('page:load', callback);
};

然后用onLoad包装我的函数,比如

onLoad(function() {
  counter()
});

onLoad函数绑定ready事件和turbolink页面:load event

答案 2 :(得分:1)

当你做

$("selector").on("click", function(){});

您实际上将选择器绑定到click事件。

如果你使用白色

$(document).on("click", "selector", function(){});

将click事件绑定到文档,在单击后检查单击的元素是否是您使用的选择器。如果是,它执行该功能。因此,只要在动态元素上绑定事件,就应该使用第二种方法。

我希望能回答&#34;为什么&#34;

的问题

答案 3 :(得分:1)

很长一段时间我不使用jQuery,但是因为我到了这里:如果你有多个带选择器“.sidebar”的元素,我相信你需要使用“.each”来绑定函数到dom上与该选择器匹配的所有元素。

有关参考,请转到此处http://api.jquery.com/each/

希望这会有所帮助,祝你好运。

答案 4 :(得分:1)

我看了一下Turbolinks,它完成了我的想法:它在主页面上的容器内加载链接的HTML内容。问题是,它加载的任何内容都与您在加载主页面时声明的任何事件和函数无关,因此实际上,在第一次单击之后,它刚刚加载的HTML上的选择器不会将click事件归因于它(当你进行绑定时它不在DOM上)。

可能的解决方案:我对.live()方法进行了一些研究,但是已被弃用,所以我建议这样做:

$(&#39; body&#39;)。on(&#39; click&#39;,&#39; a.saveButton&#39;,saveHandler)

看起来,更接近你需要的元素的绑定将确保无论Turbolinks在体内加载什么都将获得你声明的绑定。

这里有一个更详细的答案:Javascript event binding persistence

.live钩子的文档在这里:http://api.jquery.com/live/#typefn

我过去常常在我的网页上使用相同的架构,而且我确实遇到了类似于你的问题。

希望它有所帮助。

答案 5 :(得分:0)

是否应该有效..确保:

  1. 没有什么特别的冲突。
  2. 你的html结构,也许你忘了把价值放在你的帖子里。
  3. 也许是错误的路径posts.js,用CTRL + U打开然后点击post.js什么显示你的代码,如果有的话就可以了。
  4. 我尝试这样,没关系(虚拟):

    $(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>

答案 6 :(得分:0)

老实说,涉及Turbolinks的Js问题,让它高效工作的最好方法是安装jquery rails gem,添加// require jquery-Turbolinks然后删除//需要在你的Js文件中使用turbolinks

答案 7 :(得分:0)

确保您在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)

应该有助于解决问题。

答案 8 :(得分:0)

如果动态创建#post_title#body-field,您需要更改:

$('#post_title, #body-field').on('change keyup paste', counter);

对此:

$(document).on('change keyup paste', '#post_title, #body-field', counter);

在定位页面加载时不存在的元素时,您需要将事件委派给页面加载中存在的元素(在本例中为document本身)(可能#post_title#body-field)。

答案 9 :(得分:0)

关于$('#wordCountTitle')上的$('#wordCountBody')/posts/new,您是否尝试在控制台中输入其中任何一个? /posts/new的视图可能与您的索引不同,并且缺少这些ID(或者您使它们成为类或其他一些转置)。

我遇到了Turbolinks和jquery的各种问题,所以我会就如何解决你的问题提出一些建议:

  1. 使用gem 'turbolinks'将其包含在内。按照说明操作,使用Ruby(gems)方式而不是PHP方式。

  2. 使用Turbolinks意味着当加载新的“页面”时$(document).ready不会触发。解决方案是使用:$(document).on('page:load', ready)$(document).ready(ready)page:load事件是ready事件的Turbolinks版本。

  3. 其他人已提出建议,但我发现它在我的rails应用程序中非常有价值:不是直接将事件绑定到选择器$("a").click(/* function */),而是绑定到文档意味着当Turbolinks加载新页面时,文档绑定在页面加载中存活:$(document).on('click', 'a.particularAnchor', particularAnchorClicked)

  4. 考虑到您的特定代码,我会改变这一点:

    $('#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;