yiisoft / jquery-pjax

pushState + ajax = pjax
http://pjax.herokuapp.com
MIT License
144 stars 40 forks source link

Js broken after go back by "back" button in browser #10

Closed macklay closed 10 years ago

macklay commented 10 years ago

Pjax caches html content of any page by use jquery clone() function, the original html contents of each page will be overwritten by the next open page. And when we click "back" button in browser, pjax paste cloned content. Of course, this cloned html, pasted from cache, does not contain any event handlers of original code and js does not work after that

PS: cached html does not contain inline script(wich can re-init event handlers), because yii2 paste inline scripts after container, but pjax cache container html only

PS2: The problem is not completely solved, even if the container will contain scripts, because pjax cache already rendered by js container. Therefore the html for javascript in the case of the first boot and after clicking on the "back" button will be different. This will contribute to errors and bugs.

qiangxue commented 10 years ago

@tonydspaniard could you handle this?

tonydspaniard commented 10 years ago

@qiangxue sure

tonydspaniard commented 10 years ago

IMHO @macklay I think you should not attach any inline script within the contents of a pjax'ed section. I would rather create a module or external handlers (live event handlers) to any content within.

Can you show me when is the case where you are forced to use inline scripts on an ajaxed content?

macklay commented 10 years ago

@tonydspaniard, this is inline script case: any widget with view and javascript, witch could be inserted on the page any number of times

myWidgetView.php

<?php $id = $this->context->getId(); ?>
<div id="<?= $id ?>">
  <a href="#">link</a> any widget html here..
<div>
<?php $this->registerJs('new Views.MyWidget('.json_encode([
        'el' => '#'.$id,
        'customParamFromController' => $customParamFromController,
        'customParamFromController2' => $customParamFromController2,
        ...
    ]).');', \yii\web\View::POS_END); ?>

myWidget.js

var Views.MyWidget = function(options) { 
  var $el = $(options.el);

  // add internal events delegates (live event handlers) 
  $el.on('click', 'a', function()
  {
    console.log('link clicked, param from controller is '+options.customParamFromController)
  });
  ...
}
tonydspaniard commented 10 years ago

I see, but @macklay IMHO I highly recommend to modify the script so it could handle multiple widgets on the page so it can dynamically attach events to the layers as they render on the document. For example, by a certain data-... attribute, or a specific class and then it reads the ids from its data-..., etc.... that way you avoid code repetition and also the need to register the script on every widget ajax'ed rendered.

Just an idea on how that could be accomplished... Nevertheless, will review your pull request. Thanks!

tonydspaniard commented 10 years ago

This should have been fixed by https://github.com/yiisoft/jquery-pjax/pull/11