Possible conflict between script

Asked

Viewed 1,086 times

4

Good people, I use basically 4 scripts in my project.

I have two pages, one where the posts are listed and the other where you view the posts. In the current browsing model, by clicking on any posts listed the user and sent to the page with the complete post, nothing different and everything working.

The question that I’m trying to change the way posts are viewed. In the new mode when clicking on any listed post opens a Lightbox and inside this Lightbox is loaded via Ajax page with the information. So far everything would be working out if it weren’t for one detail.

The detail is that sometimes some posts may have videos. In the old model of visualization of the posts the videos ran normally, but in this attempt of new model the videos referring to the posts do nothing, it is as if they were stuck. I think some of the scripts are conflicting. Here are the scripts ::

Script by Lightbox

$(document).ready(function() {
$('.lightbox').click(function(e){
    e.preventDefault();
    $('.background, .box').animate({'opacity':'.8'}, 0);
    $('.box').animate({'opacity':'1.00'}, 0);
    $('.background, .box').css('display', 'block');
});
$('.close').click(function(){
$('.background, .box').animate({'opacity':'0'}, 0, function(){
$('.background, .box').css('display', 'none');
});          
});
$('.background').click(function(){
$('.background, .box').animate({'opacity':'0'}, 0, function(){
$('.background, .box').css('display', 'none');
});          
});
});

Script for Loading ajax

function GetXMLHttp() {
if(navigator.appName == "Microsoft Internet Explorer") {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
else {
xmlHttp = new XMLHttpRequest();
}
return xmlHttp;
}

var xmlRequest = GetXMLHttp();

function abrirPag(valor){
var url = valor;

xmlRequest.open("GET",url,true);
xmlRequest.onreadystatechange = mudancaEstado;
xmlRequest.send(null);

if (xmlRequest.readyState == 1) {
document.getElementById("conteudo_mostrar").innerHTML = "<img src='loader.gif'>";
}

return url;
}

function mudancaEstado(){
if (xmlRequest.readyState == 4){
document.getElementById("conteudo_mostrar").innerHTML = xmlRequest.responseText;
}
}

Script used to perform functions on the video like play, pause and too

$('video').mediaelementplayer({
success: function(media, node, player) {
var events = ['loadstart', 'play','pause', 'ended'];
for (var i=0, il=events.length; i<il; i++) {
var eventName = events[i];
media.addEventListener(events[i], function(e) {
$('#output').append( $('<div>' + e.type + '</div>') );
});
}
}
});

It would have 1 more video player configuration script. Such script can be viewed in the link https://github.com/johndyer/mediaelement/blob/master/build/mediaelement-and-player.js

I also took the liberty of taking a print so you can see what the execution of scripts looks like in lightbox and not in lightbox

Lightbox-less :: http://imgur.com/mphEgef With Lightbox :: http://imgur.com/xv0E3yL

I did a test and added the video player directly inside the Lightbox and did not generate any conflict, so the problem may be in loading Ajax but I do not know where

  • There was no error in the console when you did via ajax? I suggest checking some things: 1) Did the old page have any script in the head? Remember that the content loaded via ajax does not have html or head (it does not have even, right? if it is, it is an error); 2) Are there elements with the same id in the dynamically loaded content and on the main page? 3) Post somewhere (eg. Pastebin) the complete code of both the main page and one of the pages with video that does not work. It’s hard to imagine what could be happening just with the information posted.

  • 2

    I may be wrong, but it’s not exactly a conflict. It turns out that scripts loaded by scripts don’t work at all. Try the AJAX request by jQuery itself ($.ajax, $.get...). Suddenly, something in the framework itself takes this into account and solves it for you. If it doesn’t work, load the video script along with the html that fires the lightbox and invoke the mediaelementplayer in the successful callback of the AJAX request. Another possibility would be to use jQuery.on() to attach events dynamically.

  • @Brunoaugusto what I say is true, I did some tests and actually the scripts are not being loaded... The only part of the code being loaded is the one that is not script

  • @Brunoaugusto This is news to me! Do you have any references I can consult? I thought that anything returned via Ajax, in text format, that was assigned to an element via innerHTML is to be indiscriminately accepted. In what part did I make a mistake?

  • @mgibsonbr JS is not exactly my thing, so I comment kind of stepping on eggs, just for not being absolutely sure. However, years ago, there were articles, including the Micox blog (I think everyone knows Micox) with scripts that aimed to circumvent this limitation, making an Eval() of the scripts present in the response to an AJAX request. I don’t know how things are today, whether jQuery takes it into consideration and "corrects" it automatically or not. Anyway, that was wrong before and I imagine it’s still bad practice.

  • It’s not the right method, but I’ve done a little sniffing around. I changed the page that was loaded the post, by a page that has a frame, and this frame carries the page that has the post. It works as reflexes, where one loads the content of the other, after all the frame loads the page with the scripts, so leaves the content ready, and Lightbox loads the frame, and the frame no longer has scripts, so Ajax loads all information without problems. Like I said, it’s a scam, but it solved the problem of scripts that don’t load scripts. OBS :: I’m lousy with JS

  • 1

    @Brunoaugusto I get it. Anyway, you’re right, I ran a jsFiddle test that proves this: http://jsfiddle.net/7sKMa/ As far as I know, if you create an element script using document.createElement and adds this script to head, he executes. My common sense thought it was also the case to include <script></script> in the innerHTML of any element (or head or body), but I see I was wrong.

  • Ivanveloso Gambiarra or not, it’s a solution, if you want to post as an answer, be my guest. @Brunoaugusto the same goes for the things you mentioned, after all they were key in solving the problem.

  • When you load a modal with dependent elements, you will have to load the files into the modal containing the video, as the action buttons are not yet created.

Show 4 more comments

2 answers

4


The following answer aims to extend the initial discussion in the comments of the question.


According to the Specification of the W3C:

Scripts in the resulting document tree will not be executed, referenced resources will not be loaded and no XSLT will be applied.

For many programmers, AJAX is the cure for cancer of your applications. I will not go into the merit that this is extremely wrong, that obstructive Javascript is a bad practice, that the Application has to work as much as possible without Javascript and so on. BUT, this limitation prevents a rich Application from fractioning its scripts by loading itthe on demand.

Imagine an Administrative Panel that works perfectly without JS, but with it the Administrator has a faster control and an enhanced control experience.

In addition to loading frameworks and basic plugins common to all or many pages, it doesn’t make sense, for example, to upload that small file that configures or prepares resources present only in a Client registration form when we are viewing, I don’t know, the Performance Reports section, right?

Yes, these small files are harmless in an Administrative Panel which is accessed simultaneously by a few people, but the limitation "imposed" by the W3C is not restricted to this scenario.

There must be a smarter way around that limitation. For the solution proposed and described below I will be assuming that the AJAX request has been completed successfully, in view of everything happening in your callback.

I’ll be using it as a demonstration jQuery Timeago only because it is a script that fulfills a simple task. And also because it was one of the first returned in the Github listing :P

html timeago.

<html>
<head>

<script src="http://timeago.yarp.com/jquery.timeago.js" type="text/javascript"></script>

</script>

</head>

<body></body>

</html>

We have absolutely nothing more than the inclusion of the external script from the official website since I couldn’t load it on Github (not even on RAW).

To test, in this same file we could add to HTML:

<abbr class="timeago" title="2011-12-17T09:24:17Z">December 17, 2011</abbr>

And the corresponding JS in ready():

$("abbr.timeago").timeago();

And we’d have the way out 3 years ago

Well, back to the main focus, we have the second file where the AJAX request will be made:

<html>
<head>

<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>

<script type="text/javascript">

    $(document).ready(function() {

        $('#loadData').click(function(event) {

            $.ajax({

                url: 'timeago.html',

                success: function( response, status, xhr ) {

                    $("abbr.timeago").timeago();
                }
            });
        });
    });

</script>

</head>

<body>
<p>
   <a href="javascript:void(0)" id="loadData">
    Load jQuery TimeAGO
</a>

<p>
    <abbr class="timeago" title="2011-12-17T09:24:17Z">December 17, 2011</abbr>
</p>

</body>
</html>

Theoretically, by clicking on the <abbr> would be replaced by the words 3 years ago. In theory, even a woman is perfect, but there’s no point in thinking about <body> if they care how <head> (that joke is a horror)

Checking the console we see the error corresponding to the jQuery Timeago method does not exist because it was not loaded.

Let’s start the solution journey by locating the scripts in the returned request body:

var scripts = $( response ).filter( 'script' );

Then we will iterate this information and upload it to the current DOM. There are techniques that create new elements <script> and set the src and take into account particularities which given my relatively little contact with JS I will not even mention.

jQuery offers us the jQuery.getScript() that is nothing more than a shortcut to a jQuery.ajax() having the dataType properly configured to script.

We could iterate this information and make N calls to jQuery.getScript() but it brings us a problem. jQuery.getScript() only works with asynchronous requests, that is, as soon as it ends, it is already returned immediately which prevents us from using the resources of the scripts loaded in different scopes of its own callback successful.

It seemed confusing but it’s simple. Use jQuery.getScript() keeps us from doing that:

$.getScript( 'myexternalScriptFile.js' );
someFunctionfromTheFileAbove();

Allowing only that:

$.getScript( 'myexternalScriptFile.js', function() {

    someFunctionfromTheFileAbove()
})

It doesn’t seem to be a problem, but it therefore prevents a second jQuery.getScript() use some resource present in the script loaded by the first.

Fortunately the jQuery 1.5 implemented the Deferred Objects for all AJAX requests.

Because it’s an asynchronous request, logically she would need a callback however, with Deferred Objects, we have a huge advantage through the jQuery.when() which we can expand by loading multiple files but using a single callback:

$.when( $.getScript( 'scriptOne.js' ), $.getScript('scriptTwo.js') ).done( function () {
  sometgingFromScriptOne();
  somethingFromScriptTwo();
});

As a consequence, all resources of all loaded scripts would be accessible

One can already have a sense of how the final solution would look, that is, iterate and invoke jQuery.getScript() inside jQuery.when() informing a single callback for deferred.done():

jQuery.each( scripts, function( index, value ) {

    $.when( $.getScript( value.src ) ).done( doneCallback );

});

But, we have one more problem. Here we are relying on the value of the property src of the information returned when filtering the Request body searching for the tags <script>. Yes, I repeated all this to get your attention. ^_^

Routines inline, that is, those that do not come from an external origin obviously do not have an attribute src (at least one completed) and therefore not solved by jQuery.getScript().

For these cases, we have the good old, and often considered a perverse villain, val(). A simple condition and we solve the problem:

jQuery.each( scripts, function( index, value ) {

    if( value.src == "" ) {

        eval( value.text );

    } else {

        $.when( $.getScript( value.src ) ).done( doneCallback );
    }
});

Perfect... if what might have been evaluated by val() cannot under any circumstances be used by anything carried by jQuery.getScript >.<

Once again jQuery saves us through jQuery.globalEval() which does the same as the val() traditional, except that in global scope.

Needless to say, if val() can be dangerous, a val() global may be even more, certain?

The final script, from the entire file this time:

<html>
<head>

<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>

<script type="text/javascript">

    $(document).ready(function() {

        $('#loadData').click(function(event) {

            $.ajax({

                url: 'timeago.html',

                success: function( response, status, xhr ) {

                    var scripts = $( response ).filter( 'script' );

                    jQuery.each( scripts, function( index, value ) {

                        if( value.src == "" ) {

                            jQuery.globalEval( value.text );

                        } else {

                            $.when( $.getScript( value.src ) ).done( doneCallback );
                        }
                    });
                }
            });
        });
    });


    function doneCallback() {

        $("abbr.timeago").timeago();

        alert( someInlineScriptvar );
    }

</script>

</head>

<body>
<p>
   <a href="javascript:void(0)" id="loadData">
    Load jQuery TimeAGO
</a>

<p>
    <abbr class="timeago" title="2011-12-17T09:24:17Z">December 17, 2011</abbr>
</p>

</body>
</html>

Let me make a little final consideration.

In our doneCallback() we have an Alert() for a variable not described in any part of the text. Sometimes I have this bad habit when writing a text and end up writing things in a different order than I should.

This variable came from a test done as soon as I finished with the solution with jQuery.when() and it occurred to me the fact of scripts inline not having a property src filled.

In the archive html timeago. I created a simple variable, with a value also simple right after calling the external script:

<script type="text/javascript">

    var someInlineScriptvar = 'Foo';

</script>

So I was able to be sure that the solution would work in the two main scenarios, not to say unique.

Sources used in the solution:

  • It was a long answer and a bit dull, but I hope I made myself understood well, since I’m not really into Javascript. Any error, whether content or syntax, who best understands, please feel free to edit.

0

$(document).ready(function(){

$('.posts a').live('click',function(){

$('#conteudo.mostrar').load($(this).attr('href'));

return false;

});
});

that makes solves all problems

  • Okay, but the method live is no longer available in current versions of jQuery. To delegate the treatment of event nowadays, you need to use .on in some ancestor that already exists in the DOM, passing the selector as the second parameter.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.