views:

63

answers:

4

I wrote this script, but it doesn't work in way I wanted:

$(document).ready(function(){
    if ($('#map_container').find('#point').length == 0 ) {
        $("#map_container").click(function (e) { 
            var relativeXPosition = (e.pageX - this.offsetLeft);
            var relativeYPosition = (e.pageY - this.offsetTop);
            //alert('left: '+relativeXPosition+', top: '+relativeYPosition);
            $("#map_container").append('<img id="point" src="<?=url::base();?>images/city.png" alt="" />');
            $("#point").css({ top: (relativeYPosition) + 'px', left: relativeXPosition + 'px', position: 'absolute' })
        }); 
    }
});

It should put only one img with id="point", but when I click map_container two times I get two img's, why this if does not work?

+5  A: 

You say: "If the length is zero then every time the element is clicked, do a thing"

You mean: "Every time the element is clicked, if the length is zero, do a thing"

Put the test inside the event handler.

David Dorward
+2  A: 

Try this:

$(document).ready(function(){

    $("#map_container").click(function (e) { 
        if ($('#map_container').find('#point').length == 0 ) {
            var relativeXPosition = (e.pageX - this.offsetLeft);
            var relativeYPosition = (e.pageY - this.offsetTop);
            //alert('left: '+relativeXPosition+', top: '+relativeYPosition);
            $("#map_container").append('<img id="point" src="<?=url::base();?>images/city.png" alt="" />');
            $("#point").css({ top: (relativeYPosition) + 'px', left: relativeXPosition + 'px', position: 'absolute' })
        } 
    });
});

You must make the if inside the click function.

Diego
+2  A: 

You only bind the click() if there's not already an image, but within the click() (which can be invoked several times) you're not performing this check. Therefore,

$(document).ready(function(){
    $("#map_container").click(function (e) { 
        if ($(this).find('#point').length == 0 ) {
            var relativeXPosition = (e.pageX - this.offsetLeft);
            var relativeYPosition = (e.pageY - this.offsetTop);
            //alert('left: '+relativeXPosition+', top: '+relativeYPosition);
            $("#map_container").append('<img id="point" src="<?=url::base();?>images/city.png" alt="" />');
            $("#point").css({ top: (relativeYPosition) + 'px', left: relativeXPosition + 'px', position: 'absolute' })
        }
    }); 
});

To elaborate: In your code the click() handler is bound once (depending on the condition - which I suspect to always return true) but can be invoked several times always producing the same output. In the above, however, the click() handler performs the check on every invocation, thus only producing output when the condition is false (i.e., there is no #point yet).

EDIT: unbind() / one()
@tsimbalar has a pretty neat solution using unbind(). That's clever if your click() does not contain an else part (to be executed if #point does exist). The same can be achieved by means of one(): $(...).one('click', function() { ... });

$(document).ready(function(){
    $("#map_container").one('click', function (e) { 
        var relativeXPosition = (e.pageX - this.offsetLeft);
        var relativeYPosition = (e.pageY - this.offsetTop);
        //alert('left: '+relativeXPosition+', top: '+relativeYPosition);
        $("#map_container").append('<img id="point" src="<?=url::base();?>images/city.png" alt="" />');
        $("#point").css({ top: (relativeYPosition) + 'px', left: relativeXPosition + 'px', position: 'absolute' })
    }); 
});
jensgram
@jensgram : I didn't know about the `one()` ... really nice !
tsimbalar
+1 for the editing to give detailed examples !
tsimbalar
+2  A: 

I understand that what you want is that the code for the click event should be executed only once.

Something like this would be better, I think :

$(document).ready(function(){
        $("#map_container").click(function (e) { 
            var relativeXPosition = (e.pageX - this.offsetLeft);
            var relativeYPosition = (e.pageY - this.offsetTop);
            //alert('left: '+relativeXPosition+', top: '+relativeYPosition);
            $("#map_container").append('<img id="point" src="<?=url::base();?>images/city.png" alt="" />');
            $("#point").css({ top: (relativeYPosition) + 'px', left: relativeXPosition + 'px', position: 'absolute' })
            //we are done here, do not react to clicks anymore !
            $(this).unbind('click')
        });
});

note the unbind, saying you do not want to be called when a click occurs.

tsimbalar