Search code examples
javascriptajaxmootools

Javascript file not executing after AJAX call


When I make an AJAX call to replace a div, the response contains a script tag pointing to an external .js file. However, I can't get the returned JS to execute. I've tried to eval() the response but that didn't work. I also tried to call a function inside the external .js file from within the onComplete callback, but this also does not work. Not sure what else to do. I'm using mootools core 1.4.5

Main page's JS

window.addEvent('domready', function(){  

    function ajaxfunc(i)
    {
        return function(e){
            e.stop();
            var requestData = new Request({
               url: 'blah.php?cat=' + i,
               evalScripts: true,
               evalResponse: true,
                   onComplete: function(response){
                       $('rt-main').set('html', response);
                   }
            });
            requestData.send();
        };
    }

    var total = $('cat_table').getChildren('div').length;
    for(var i=1; i<=total; i++)
    {
       $('catClick'+i).addEvent('click', ajaxfunc(i));
    }


});

The returned HTML

<script src="listings.js" type="text/javascript"></script>
...(other markup, etc)

And inside that listings.js file

window.addEvent('domready', function(){  

    function gotoItem(i)
    {
       return function(e){
          e.stop();
          var id= i;
          var requestData = new Request ({
             url: 'blah.php?id='+id,
             onComplete: function(response){
                $('rt-main').set('html', response);
             }
          });
          requestData.send();
       };
    }

   $$('.itemBox').each(function(el){
      el.getElement('a.itemClick').addEvent('click', gotoItem(el.id)); 
   });

});

The environment I'm working in is Joomla 3.1 in case that affects anything.


Solution

  • No domready will fire a second time for you as per listings.js, your DOM is already ready.

    You could manually do window.removeEvents('domready') beforehand, then load via XHR and do window.fireEvent('domready') to run it.

    If you use event delegation you can avoid having to run any js after initial ajax requests, all you'd need is something like this.

    window.addEvent('domready', function () {
        var ct = document.id('cat_table'),
            divs = ct.getChildren('div'), //need a more qualified selector
            rtMain = document.id('rt-main');
    
        divs.each(function(el, i){
            // store the index, if you don't have it as an attribute like id, rel or data-id
            el.store('index', i);
        });
    
        ct.addEvent('click:relay(div)', function(e){ // needs more qualified also.
            e && e.stop();
    
            new Request({
                method: 'get', // not post, check - faster
                url: 'blah.php?cat=' + this.retrieve('index'),
                evalResponse: true,
                onComplete: function(){
                    rtMain.set('html', this.response.text);
                }
            }).send();
        });
    
        // delegation, assumes .itemBox are children of rtMain - just delegate to other parent otherwise.
        rtMain.addEvent('click:relay(.itemBox)', function(e){
            // reliance on index in collection is bad, try to change response above to contain data-id.
            e.stop();
    
            new Request({
                method: 'get',
                url: 'blah.php?id=' + this.get('data-id'), 
                onComplete: function(){
                    rtMain.set('html', this.response.text);
                }
            }).send();
        });
    });
    

    keep in mind you had a reliance on the index of the item in the Elements collection, which is less than safe. use a hard db id, provided by the backend. this is insecure, ppl can mod their DOM, delete elements and get to ids they should not see. Not that they can't do so otherwise but...

    Bringing in scripts via XHR and evaling responses is an anti-pattern and gives a vector of attack on your page for XSS, don't forget that.