views:

48

answers:

2

OK, so here's what I'm trying to do:

I have a landing page with 3 buttons on it, and I have 3 corresponding external swf files, one for each button... so the user clicks a button and the corresponding swf file is loaded into an empty MC on the stage. Now each of these external swf files also contains several buttons and each of these buttons when clicked will fire off a click event, each buttons event in each swf is uniquely named based on the button name and the swf file name (ex: swf1_button1_click) So in the main swf file after a button is clicked I loop through the 3 main buttons and add listeners to the contents of the empty holder clip for each of the buttons so its listening for "swf1_button1_click", "swf1_button2_click", "swf2_button1_click"... so on and so forth.

Now this all works, clips load in correctly, events fire and are heard approperatly meaning the empty clip does recieve the "swf1_btn1_click" event and it fires the code associated with that event correctly, but the problem is with the function being called, Here is the code in question...

The function for loading the external swf files:

function loadCommunity(e:MouseEvent) {
 var mLoader:Loader = new Loader();
 var community:String = MovieClip(e.currentTarget).name;
 trace("Loading " + community);
 var mRequest:URLRequest = new URLRequest(DevSite+"/flash/" + community + ".swf?community=" + community);
 mLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, displayCommunity);
 mLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, function(e:ProgressEvent) {
  var percent:Number = e.bytesLoaded / e.bytesTotal;
  percent = Math.round(percent * 100);
  trace(percent + "% loaded");
 });
 mLoader.load(mRequest);
}

The code for assigning the event listeners:

function displayCommunity(e:Event) {
 for (var i = 0; i < mcCommunityHolder.numChildren; i++) {
  mcCommunityHolder.removeChild(mcCommunityHolder.getChildAt(i));
 }
 mcCommunityHolder.alpha = 0;
 mcCommunityHolder.visible = true;
 mcCommunityHolder.addChild(e.currentTarget.content);
 TweenLite.to(mcCommunityHolder, 1, {alpha:1, easing:Elastic.easeOut});
 var newClip:MovieClip = MovieClip(mcCommunityHolder.getChildAt(mcCommunityHolder.numChildren - 1));

 for each (var mc:MovieClip in mcCommunities) {
  var commName:String = mc.name.toLowerCase();
  trace(" ... " + commName + " ... ");
  newClip.addEventListener(commName + "_btnMap", function(e:Event) { trace("clicked: " + commName); viewLotmap(commName); });
  newClip.addEventListener(commName + "_btnLocation", function(e:Event) { trace("clicked: " + commName); viewLocationmap(commName); });
  newClip.addEventListener(commName + "_btnAriel", function(e:Event) { trace("clicked: " + commName); arielPhotos(commName); });
  newClip.addEventListener(commName + "_btnRegister", function(e:Event) { trace("clicked: " + commName); communityRegister(commName); });
 }
}

So what I'm getting is: no matter what external swf's button I have clicked the events of the buttons within it act as though I where clicking a button from within external swf 3... make sense?

heres an example: I click Button1, external swf 1 loads and displays, within external swf 1 I click button 1 which fires off its event "swf1_btn1_click" and the main swf sees it as such, but when this function ("communityRegister(commName);") is called within the listener event, "commName" is always the same value (the value that btn3 of the main swf should have).

So my main flash piece is treating every external swfs events as though they where coming from external swf 3. The best way I can explain it is: Its treating "commName:String" as if it where a reference variable and when I resign it on every iteration of the loop, the previous uses of it also change to the new value so every time I've used it is always set to the value of the last time it where assigned...

Gahh!!, what a brain wreck, haha... I've had this issue many times before and never actually figured it out. I've always just managed to re work the code until it fixed its self, but I'm tire of doing that and I want to know why this happens. I'm not interested in other ways of coding what I want to do, I need to know what is going on to cause this sort of behaviour so don't be shy about getting technical ;)

Thanks in advance.

A: 

I think you've already found out the problem. All event listeners end up with a reference to the commName created in the last iteration of your loop.

There are some ways around this. Off the top of my head:

  for each (var mc:MovieClip in mcCommunities) {
  var commName:String = mc.name.toLowerCase();
  trace(" ... " + commName + " ... ");
  newClip.commName = commName;
  newClip.addEventListener(commName + "_btnMap", function(e:Event) { trace("clicked: " + e.target.commName); viewLotmap(e.target.commName); });
  newClip.addEventListener(commName + "_btnLocation", function(e:Event) { trace("clicked: " + commName); viewLocationmap(e.target.commName); });
  newClip.addEventListener(commName + "_btnAriel", function(e:Event) { trace("clicked: " + e.target.commName); arielPhotos(e.target.commName); });
  newClip.addEventListener(commName + "_btnRegister", function(e:Event) { trace("clicked: " + e.target.commName); communityRegister(e.target.commName); });
 }

Here the idea is that since MovieClip is dynamic, you can add commName as a property. Then, in the event handler you acces that value from the mc instance.

Other option could be this:

 for each (var mc:MovieClip in mcCommunities) {
  var commName:String = mc.name.toLowerCase();
  trace(" ... " + commName + " ... ");
  setEvents(newClip,commName);
 }

 function setEvents(mc:MovieClip,commName:String):void {
  mc.addEventListener(commName + "_btnMap", function(e:Event) { trace("clicked: " + commName); viewLotmap(commName); });
  mc.addEventListener(commName + "_btnLocation", function(e:Event) { trace("clicked: " + commName); viewLocationmap(commName); });
  mc.addEventListener(commName + "_btnAriel", function(e:Event) { trace("clicked: " + commName); arielPhotos(commName); });
  mc.addEventListener(commName + "_btnRegister", function(e:Event) { trace("clicked: " + commName); communityRegister(commName); }); 
 }

Passing commName as an argument should prevent that the mcs share the same value.

Juan Pablo Califano
Excelent! I get it now, Not sure why I didn't see that before but I do now, thanks for the help :)
gbinflames
A: 

Edit: Doh, haha I just re-read the comment above and this method is actually the second suggestion he made, I was a bit to eager to try his first suggestions and fail... oh well, I'm gonna leave this original comment here though because it explains why the first suggestion won't work and the second one does...

Ok, so your explanation is sound but your solution doesn't work... Here is why:

you said to add a property to the movieclip that contains the value of "commName" to eliminate the reference variable issue which is what is needed (although "commName" is just assigned the value of "mc.name" so you could just use "mc.name" instead) but the referencing issue still exists because we're in a for loop...

for each (var mc:MovieClip in mcCommunities)...

So "mc" is still seen as a reference variable and we still get the same undesired results (every objects event acts as though it where the last object in the row being clicked...)

So how do we fix it... Well, what I ended up doing was changing the "for each" to a "for (var i:int...) and grabbing "mc" by using a "getObjectAt(i)" which at first I thought would work but turns out that we still have a variable that's acting like a reference and this time it was "i:int" in the iteration... so this:

for (var i:int = 0;  i < mcCommunities.numChildren; i++) {
MovieClip(mcCommunities.getChildAt(i)).name);   ...

where mcCommunities.numChildren is 3 (0,1,2) caused i to equal 3 (not a valid index) when the loop exited and everywhere I had set "MovieClip(mcCommunities.getChildAt(i)).name);" before hand now had 3 as a value for i as well... fustration

So the final working solution was as follows:

function displayCommunity(e:Event) {
    for (var i = 0; i < mcCommunityHolder.numChildren; i++) {
        mcCommunityHolder.removeChild(mcCommunityHolder.getChildAt(i));
    }
    mcCommunityHolder.alpha = 0;
    mcCommunityHolder.visible = true;
    mcCommunityHolder.addChild(e.currentTarget.content);
    TweenLite.to(mcCommunityHolder, 1, {alpha:1, easing:Elastic.easeOut});

    for (var j:int = 0;  j < mcCommunities.numChildren; j++) {
        assignListeners(MovieClip(mcCommunityHolder.getChildAt(mcCommunityHolder.numChildren - 1)), MovieClip(mcCommunities.getChildAt(j)).name);
    }
}

function assignListeners(newClip:MovieClip, commName:String) {
    newClip.addEventListener(commName + "_btnMap", function(e:Event) { trace("clicked: " + commName); viewLotmap(commName); });
    newClip.addEventListener(commName + "_btnLocation", function(e:Event) { trace("clicked: " + commName); viewLocationmap(commName); });
    newClip.addEventListener(commName + "_btnAriel", function(e:Event) { trace("clicked: " + commName); arielPhotos(commName); });
    newClip.addEventListener(commName + "_btnRegister", function(e:Event) { trace("clicked: " + commName); communityRegister(commName); });
}

What I did was take the assigning of eventListeners out and placed it in a function so now everywhere that was causing a reference variable before was now being assigned via function paramaters which are only in scope of the function its self so every time you call it you can be sure the values will be what your sending in ;) satisfaction

Anyhow, thanks for pointing me in the right direction, I got my head wrapped around this now and I can find some other seeming illogical issue to pull my hair out over :)

Peace

gbinflames