Prodigga
Prodigga

Reputation: 1477

Variables going beyond scope?

my code:

<html>

<head>

<script type="text/JavaScript" src="jquery-1.3.2.min.js"></script>
<script type="text/JavaScript" src="jquery.center.js"></script>
<script type="text/JavaScript">
    $(document).ready(function(){
        $('a').click(function(){
            popup_AskYN("Want me to tell you what 1 + 1 is?",function(){
                //popup_Info("It's 2, silly!");
            },function(){
                //popup_Info("I didn't want to, anyway!");
            });
        });
    });

    function popup_AskYN(msg,yes_fn,no_fn){
        $('body').append("<div id='popup'><p>"+msg+"</p><a id='popup_yes' href='#'>Yes!</a><a href='#' id='popup_no'>No.</a></div>");
        var yes_button = $('#popup_yes:last');
        var no_button = $('#popup_no:last');
        var popup = $('#popup:last');
        popup.center();

        yes_button.click(yes_fn);
        no_button.click(no_fn);

        yes_button.click(function(){
            popup.fadeOut('fast').remove();
        });
        no_button.click(function(){
            popup.fadeOut('fast').remove();
        });
    }

    function popup_Info(msg,callback){
        $('body').append("<div id='popup'><p>"+msg+"</p><a id='popup_ok' href='#'>Ok.</a></div>");
        var ok_button = $('#popup_ok:last');
        var popup = $('#popup:last');
        popup.center();

        ok_button.click(callback);

        ok_button.click(function(){
            popup.fadeOut('fast',function(){ $(self).remove(); });
        });
    }


</script>

<style type="text/css">
#popup {
    position:absolute;
    border:1px solid black;
}
#popup a {
    margin:10px;
}
</style>

</head>

<body>
<a href="#">Launch the popup!</a>
</body>

Now this works well..except for when i have more than one popups. What i've narrowed it down to is when-ever i create a new popup, it changes the value of yes_button,no_button,ok_button and popup. So when the previous popup tries to use these variables, they all point to the new popup and not the current one. since all the popup's have the same id, i don't have anything "unique" to identify each by. i figured simply storing the selector would be enough but thats not working. what can i do here?

edited, added proper id's, but still not working...:

<html>

    <head>
    <title>Call backs</title>

    <script type="text/JavaScript" src="jquery-1.3.2.min.js"></script>
    <script type="text/JavaScript" src="jquery.center.js"></script>
    <script type="text/JavaScript">
        $(document).ready(function(){
            $('a').click(function(){
                popup_AskYN("Want me to tell you what 1 + 1 is?",function(){
                    //popup_Info("It's 2, silly!");
                },function(){
                    //popup_Info("I didn't want to, anyway!");
                });
            });
        });

        var popup_AskYNId = 0;
        var popup_InfoId = 0;
        function popup_AskYN(msg,yes_fn,no_fn){
            popup_AskYNId = popup_AskYNId + 1;
            $('body').append("<div class='popup' id='"+popup_AskYNId+"popup_AskYN'><div class='popup_inner'><p>"+msg+"</p></div><div class='popup_options'><a class='popup_yes' id='"+popup_AskYNId+"popup_yes_AskYN' href='#'>Yes!</a><a href='#' class='popup_no' id='"+popup_AskYNId+"popup_no_AskYN' >No.</a></div></div>");
            popup = $('#'+popup_AskYNId+'popup_AskYN');
            yes_button = $('#'+popup_AskYNId+'popup_yes_AskYN');
            no_button = $('#'+popup_AskYNId+'popup_no_AskYN');

            popup.center();

            yes_button.click(yes_fn);
            no_button.click(no_fn);

            yes_button.click(function(){
                popup.fadeOut('fast').remove();
            });
            no_button.click(function(){
                popup.fadeOut('fast').remove();
            });
        }

        function popup_Info(msg,callback){
            $('body').append("<div id='popup'><div id='popup_inner'><p>"+msg+"</p></div><div id='popup_options'><a id='popup_ok' href='#'>Ok.</a></div></div>");
            ok_button = $('#popup_ok:last');
            popup = $('#popup:last');
            popup.center();

            ok_button.click(callback);

            ok_button.click(function(){
                popup.fadeOut('fast',function(){ $(self).remove(); });
            });
        }


    </script>

    <style type="text/css">

    .popup {
        position:absolute;
        border:1px solid black;
        padding:3px;
    }
    .popup_inner {
        border:1px solid black;
        padding:10px;
    }
    .popup_options {
        margin:0 auto;
    }
    .popup_options a {

        border:1px solid black;

        margin-top:3px;
        margin-left:3px;
        height:15px;
        width:75px;
        float:right;

        text-align:center;
        font-family:tahoma;
        font-size:0.8em;
        text-decoration:none;
        line-height:14px;
    }

    </style>

    </head>

    <body>
    <a href="#">Launch the popup!</a>
    </body>

</html>

solution was found, but i modified it a little bit so that yes and no accepted functions like the old version..

    $(function() {
  $('a').click(function(e) {
    e.preventDefault();

    var num1 = Math.floor(Math.random()*11),
    num2 = Math.floor(Math.random()*11);

    popup_AskYN(
        "Want me to tell you what 1 + 1 is?",
        function(){
            $('body').append('its 2');
        },function(){
            $('body').append('Fine.');
        });;
  });

  $('.popup_yes').live('click', function(e) {
    e.preventDefault();

    $(this).closest('.popup').fadeOut('fast', function() {
      $(this).remove();
    });
  });
  $('.popup_no').live('click', function(e) {
    e.preventDefault();

    $(this).closest('.popup').fadeOut('fast', function() {
      $(this).remove();
    });
  });

});

function popup_AskYN(msg, yes, no){
  $('body').append("<div class='popup'><div class='popup_inner'><p>"+msg+"</p></div><div class='popup_options'><a class='popup_yes' href='#'>Yes!</a><a href='#' class='popup_no'>No.</a></div></div>");
  var yes_button = $('.popup_yes:last');
  var no_button = $('.popup_no:last');
  var popup = $('.popup:last');

  yes_button.click(yes);

  no_button.click(no);
}

Upvotes: 0

Views: 180

Answers (3)

Jimmy
Jimmy

Reputation: 37081

This works fine for me if I simply change all the IDs to classes. Centering the popups absolutely on the screen doesn't lend itself to having multiple instances of a popup, though, if that's what you're after. I had to comment out the centering/positioning code to see that it was working.

I would also recommend that when someone clicks the yes or no links in a popup, the answer replaces the original popup's content instead of creating a new popup. I see that you're attempting to have the question fade out before the answer appears, but notice that in your current implementation, the original popup question is removed before the animation finishes, so there's no advantage to removing the question and creating a new popup window with the answer as opposed to just replacing the content.

If you want the question to fade out before the answer appears, one option would be to only remove the question popup after the animation completes, which you can do with fadeOut's second parameter, which is a callback to be executed when the animation completes. Again, this doesn't lend itself to having multiple instances of popup questions, though. The reason is because the answer popup is disassociated from the question popup with your method of removing the question and appending the answer to the body. This would also be solved by simply replacing the question with the answer. If you still want the same fade effect, you can fade the popup out, then change its contents, then fade it back in.

Here is a version of your code that works and changes it as I suggest:

<html>
<head>
  <script type="text/JavaScript" src="http://code.jquery.com/jquery.js"></script>
  <script type="text/JavaScript">
    $(function() {
      $('a').click(function(e) {
        e.preventDefault();

        var num1 = Math.floor(Math.random()*11),
        num2 = Math.floor(Math.random()*11);

        popup_AskYN(
          "Want me to tell you what " + num1 + " + " + num2 + " is?",
          "It's " + (num1 + num2) + ", silly!",
          "I didn't want to, anyway!"
        );
      });

      $('.popup_ok').live('click', function(e) {
        e.preventDefault();

        $(this).closest('.popup').fadeOut('fast', function() {
          $(this).remove();
        });
      });
    });

    function popup_AskYN(msg, yes, no){
      $('body').append("<div class='popup'><p>"+msg+"</p><a class='popup_yes' href='#'>Yes!</a><a href='#' class='popup_no'>No.</a></div>");
      var yes_button = $('.popup_yes:last');
      var no_button = $('.popup_no:last');
      var popup = $('.popup:last');

      yes_button.click(function() {
        popup.html('<p>' + yes + '<a class="popup_ok" href="#">Ok.</a>');
      });

      no_button.click(function() {
        popup.html('<p>' + no + '<a class="popup_ok" href="#">Ok.</a>');
      });
    }
  </script>

  <style type="text/css">
  .popup {
    border:1px solid black;
    margin-bottom: 10px;
  }
  .popup a {
    margin:10px;
  }
  </style>
</head>

<body>
  <a href="#">Launch the popup!</a>
</body>

Upvotes: 1

slebetman
slebetman

Reputation: 113866

I see you keep appending a div to the document with id=popup and a lot of other stuff with hardcoded ID. In HTML IDs must be unique throughout the whole document and a particular ID (eg 'popup') must only appear once. What happens when two elements share the same ID is undefined and the browser can return anything the browser's developer feel like.

So your query $('#popup:last') does not do what you think it means.

In cases like this regular DOM methods work much better than jQuery-ism:

// shortcut. I hate typing document...
function newElement (tag, spec) {
    var el = document.createElement(tag);
    for (var n in spec) {
        el[n] = spec[n];
    }
    return el;
} 

function popup_AskYN(msg,yes_fn,no_fn){
    // because we get the references directly we don't need to
    // assign ids and therefore avoid id collisions:

    var popup = $(newElement('div')).append($(newElement('p')).append(msg));
    var yes_button = $(newElement('a',{href:'#'})).append('Yes!');
    var no_button = $(newElement('a',{href:'#'})).append('No.');

    popup.append(yes_button).append(no_button);
    popup.center();

    yes_button.click(yes_fn);
    no_button.click(no_fn);

    yes_button.click(function(){
        popup.fadeOut('fast').remove();
    });
    no_button.click(function(){
        popup.fadeOut('fast').remove();
    });

    $('body').append(popup);
}

Upvotes: 1

Sam Tyson
Sam Tyson

Reputation: 4616

You can create a unique identifier using the number of existing popups.

var popupId =  $("#popup").size();

Then create the new popup using the id and reference it for the buttons as well.

$('body').append("<div id='" + popupId + "'><p>"+msg+"</p><a id='popup_ok' href='#'>Ok.</a></div>");

Upvotes: 0

Related Questions