Jon Mitten
Jon Mitten

Reputation: 2055

Flash Button clicks don't work

I have 4 instances of the same basic button object (a rectangle). The button Class is called LinkButton, with the Name of LinkButton, and each instance is button_1, _2, _3, and _4. I am using the following ActionScript:

import flash.net.navigateToURL;
import flash.net.URLRequest;
import flash.events.Event;
import flash.display.MovieClip;
import flash.events.MouseEvent;
import fl.motion.MotionEvent;

this.button_1.addEventListener(MouseEvent.CLICK, fl_ClickToGoToWebPage("http://google.com"));
this.button_2.addEventListener(MouseEvent.CLICK, fl_ClickToGoToWebPage("http://adobe.com"));
this.button_3.addEventListener(MouseEvent.CLICK, fl_ClickToGoToWebPage("http://amazon.com"));
this.button_4.addEventListener(MouseEvent.CLICK, fl_ClickToGoToWebPage("http://ask.com"));

function fl_ClickToGoToWebPage(url:String) {
    navigateToURL(new URLRequest(url), "_blank");
}

When I publish and run from a web server, a new (blank) page opens to google.com - I don't click, it just opens automatically. None of the other pages open, however. And, of course, I really only want these URLs to open on a click event. What have I done wrong here?

Upvotes: 1

Views: 575

Answers (1)

BadFeelingAboutThis
BadFeelingAboutThis

Reputation: 14406

The reason for this, is when you add a callback for an event, you pass it a reference to a function.

What you are doing however, is passing the result of the function. (so at the time you add the listener, you are actually running the method fl_ClickToGoToWebPage with the supplied values.)

What you want is this:

this.button_1.addEventListener(MouseEvent.CLICK, fl_ClickToGoToWebPage);

You can pass the data (url) a few different ways.

  1. use a switch statement in the handler:

    This solution is pretty good, it's simple though perhaps not as encapsulated as other ways.

    //you get a reference to the button that was clicked with the event's current target property.
    function fl_ClickToGoToWebPage(event:Event) {
        var url:String;
        switch(event.currentTarget){
            case button_4:
                url = "http://ask.com";
                break;
    
            case button_3:
                url = "http://amazon.com";
                break;
    
            //etc for the other buttons
        }
        navigateToURL(new URLRequest(url), "_blank");
    }
    
  2. Assign a dynamic property to each button.

    This solution is the most encapsulated, as the data is attached to the actual button, but dynamic vars are prone to spelling mistakes etc and won't be checked by the compiler.

    //if button_1 is a MovieClip or other dynamic class, you can just make up a property on it like this:
    this.button_1.url = "http://google.com";
    this.button_1.addEventListener(MouseEvent.CLICK, fl_ClickToGoToWebPage);
    
    //..repeat for the rest of the buttons
    
    
    //then, in the handler, the event.currentTarget is a reference to the button that was clicked:
    
    function fl_ClickToGoToWebPage(event:Event) {
        navigateToURL(new URLRequest(event.currentTarget.url), "_blank");
    }
    
  3. Create a class file for your LinkButton and add a public url property

    This is most elegant solution, but for just one property it may be a bit overkill. Create a file called LinkButton.as and place it next to your .fla.

    Add this to the file:

    package {
        public class LinkButton extends MovieClip {
            public var url:String;
        }
    }
    

    Though, even better, would be the encapsulate all the functionality of the LinkButton into it's own class file:

    package {
        public class LinkButton extends MovieClip {
            public var url:String;
    
            public function LinkButton(){
                this.addEventListener(MouseEvent.CLICK, clickHandler);
            }
    
            private function clickHandler(e:MouseEvent):void {
                if(!url) return;
                navigateToURL(new URLRequest(url), "_blank");
            }
        }
    }
    
    //this way, all you have to do in your timeline is set the url of each button.
    

    Now you have a url property for all LinkButton's, use this property the same way as the previous solution. The difference, is now you have compile time checking.

  4. Use an annoymous function as the return value

    This solution is dangerous and prone to memory leaks if you have the need to add listeners dynamically or need to remove/re-add listeners.

    The idea is, you call a function with your parameters, that then returns another function used as the handler.

      this.button_1.addEventListener(MouseEvent.CLICK, createButtonHandler("http://google.com"));
    
      function createButtonHandler(url:String):void {
          return function(e:Event){
              navigateToURL(new URLRequest(url), "_blank");
          }
      }
    

    The problem here, is that you have no way of referencing this function again. As such, it will stay in memory forever even if you remove your button from the screen and null it's placeholders (vars).

Upvotes: 3

Related Questions