View Full Version : swfAddress: differentiating between onChange events
milkmit
June 18th, 2009, 09:23 AM
Is there any way to differentiate between the origin of onChange events?
I understand that both come from the browser (or more specifically, the javascript side of things), I think, but my app specifically requires me to separate the two, as not all app change events will fire a new title/url (but still need to be processed in the same way as the ones that DO fire new title/url changes).
This goes against Rostislav's suggestion (http://www.asual.com/blog/swfaddress/?permalink=swfaddress-bad-practices.html), but I just don't see any way around it.
I'd basically only like to process the onChange events that come as a result of entering a URL directly, OR using the back/forward/history entries....and keep all other navigation happening in Flash separate.
Thanks!
.ral:cr
June 18th, 2009, 10:40 AM
so basically if you have 5 buttons when you press one of them you want to change the page but you don't want to change the address? and when you provide a url to jump to the correct page? how do you get that url's in the first place? you enter it manually? what's the point?
HotN
June 18th, 2009, 10:43 AM
The way I've handled this in the past is to create a static function in one of your classes that controls all URL changes that are made by your application, not the browser. Allow a String param that will be the new URL. Then, create a boolean class variable that will monitor whether the change is coming from an internal source. That way when onChange is called, you've got the boolean to determine the source. For example:
private var internalChange:Boolean = false;
public static function changeURL(newURL:String):void {
internalChange = true;
SWFAddress.setURL(newURL);
}
public function onChange(evt:SWFAddressEvent):void {
if (internalChange) {
//the URL as been changed by your app
//do something
internalChange = false;
}
else {
//the URL has been changed via the address bar
//do something else
}
}
I can't remember all the SWFAddress classes and functions off the top of my head but hopefully you get the idea.
milkmit
June 18th, 2009, 10:51 AM
Sorry if I haven't explained it well enough. Maybe part of it is just my lack of understanding of how swfAddress works.
From what I understand, any time you use setValue with swfAddress, it appends your value to the URL of your site. And every time the value is changed via setValue, an event is fired back in Flash which onChange captures and processes.
According to Rostislav's blog, the proper way of handling it is to ONLY send out the setValue command when you need a state change in Flash, and NOT do the animation etc in Flash immediately after. Instead, that navigation logic (showing or nor showing content based on what button was hit, for instance), should be inside the onChange function, and should react to the URL change event, and NOT directly to the button event in Flash.
While this all makes sense, it seems that it would only be ideal for static sites, where the sections are known (by name), and the URL change reflects *all* major navigation (and vice versa).
In my case, there will be some pretty major navigation changes that won't require a new URL/history entry, such as choosing a new date to start browsing at. Filtering, on the other hand, or clicking on any of the timeline entries, *will*, though.
So my challenge is not only separating this navigation logic into what changes the URL and what doesn't, but also trying to basically parse the incoming URL (on a browser change which fires onChange) and build out the Flash UI/content accordingly...all without worrying about duplicated navigation logic.
I seriously have no clue how this can be done... :/
milkmit
June 18th, 2009, 10:59 AM
The way I've handled this in the past is to create a static function in one of your classes that controls all URL changes that are made by your application, not the browser. Allow a String param that will be the new URL. Then, create a boolean class variable that will monitor whether the change is coming from an internal source. That way when onChange is called, you've got the boolean to determine the source. For example:
private var internalChange:Boolean = false;
public static function changeURL(newURL:String):void {
internalChange = true;
SWFAddress.setURL(newURL);
}
public function onChange(evt:SWFAddressEvent):void {
if (internalChange) {
//the URL as been changed by your app
//do something
internalChange = false;
}
else {
//the URL has been changed via the address bar
//do something else
}
}
I can't remember all the SWFAddress classes and functions off the top of my head but hopefully you get the idea.
Ahh, interesting. Ok, cool, this is actually in line with what I was thinking might work, but I wasn't sure how well it would pan out in practice.
This *should* be relatively easy for me to implement, as I dumped all the swfAddress functions into its own proxy class (URLChange.as), which is a child of my Main.as class that spawns the rest of the UI. In addition, I have a few custom events (each with a small handful of custom properties to communicate the state change) firing every time a major navigation change is made, which the Main.as parent class captures to process. One event for the topic filtering, another event for the date chooser, etc.
Anyway, from here (where the events are captured in Main.as), I could determine whether or not the navigation change should alter the URL, and then make a call to URLChange to initiate the change.
And if I use that boolean value (not sure where I should put that? I have a globalSettings singleton that all other classes see an instance of, so maybe there?), which is reset to false after each use....then I suppose it could work.
Thanks for this. I will give it a crack and post back about the outcome.
.ral:cr
June 18th, 2009, 11:34 AM
it depends how you design your framework, i'm using swfaddress for very dynamic websites. how i do it is with a a class that stores the name of the page and dispatches events when the url changes.
something like this:
SWFPages.init ("Mișcarea de reciclare");
SWFPages.registerPage ( null, welcome);
SWFPages.registerPage ( "Welcome", welcome);
SWFPages.registerPage ( "Home", home);
SWFPages.registerPage ( "Miscarea de reciclare", reciclare);
SWFAddress.onChange = SWFPages.onChange;
so my SWFPages is analyzing what page is in the url then call one of that functions.
in that function you get all the elements from the url with SWFAddress.getPathNames();
and you modify the content accordingly. i don't know how you create the pages but i have a class for each of them (if they are totally different) or a single page that updates depending on the parameters passed. if the same page is called with different parameters i'm just updating the content, i'm not creating it again. something like this:
function welcome(){
var arr = SWFAddress.getPathNames();
if (page is Page1)
page.update(arr[1], arr[2]);
else
page = new Page1 (arr[1], arr[2]);
}
hope it helps to see the logic differently
milkmit
June 18th, 2009, 09:42 PM
Thanks, ral:cr, that's something I've considered, though I'm not sure my method would wind up being so graceful.
I've realized what my other issue is with this soft of approach. I'm actually building this entire app/site to be loaded within a wrapper, because one of the main requirements is that it can be used as a chapter within a different topic-specific website, in addition to its main purpose of being a stand-alone site. This means I have to separate all of the tracking and deep-linking logic, as the implementation of these two things will be dictated by where this is loading from.
As such, I've decided to dump all of the swfAddress stuff into its own class that is a child of the wrapper class, *not* the Main.as class I'd mentioned above. So it looks like this:
There is a Wrapper.swf (document class: Wrapper.as) which loads into it the Main.swf (document class: Main.as), which is the timeline itself.
In the Wrapper.swf there is a class called SWFAddressProxy.as, which handles all of the URL changes. It is a child of the Wrapper.as document class.
The Main.swf which loads into the Wrapper.swf as a child contains all of the navigation and site logic. It is intended work as a stand-alone when required, with the only dependent function being an init() call from the parent wrapper once it's added to the stage.
Now, since the wrapper isn't always going to be there (at least in the same form), it doesn't seem that I can expect swfAddress (which is inside the wrapper) to handle any navigation logic within the timeline, since swfAddress won't always be there in all implementations of this project.
Anyway, I've did some more thinking and think I have a solution (will explain it if it winds up panning out), but I just wanted to give some more info for anyone that might be following this. Thanks!
milkmit
June 18th, 2009, 10:31 PM
Ok, I'm going to jump the gun and explain the solution I've devised (with the help from you guys!):
The onChange() function which handles swfAddress URL changes is inside the SWFAddressProxy class I mentioned above. This gets called from the Wrapper swf, which is listening for a URLChange event from the child timeline.
Once this onChange() function gets the call, it will either do nothing, or dispatch an event back to the Wrapper with UI/content change instructions.
Now, one of the arguments that's passed during this call to the SWFAddressProxy is a 'changeFromFlash' boolean, which is set to false by default. So basically, every call that's made from Flash on a nav change has this set to true, and if it's set to true it will *not* do any UI/content changes in Flash, and then it will reset changeFromFlash back to false. Flash will make its own UI/content changes independent of the swfAddress title/URL change.
But when an event comes back into the SWFAddressProxy (from the browser, on URL change via history etc) and fires the onChange function it will check to see that changeFromFlash is false (again, the default unless specifically overridden), and then dispatch an event with the URL in it up to the Wrapper, which will then parse the URL and call a function in the Timeline (via a public API for this purpose) to set the environment accordingly.
I don't know if this all makes much sense to everyone, but it seems to work in my mind. The classes/SWFs are comfortably decoupled, as the Timeline API is passive and not required to function...but *if* there is a wrapper with a swfAddress proxy listener present, it will pick up on those event change requests from the Timeline, do its swfAddress magic, and only call those Timeline API methods when needed if swfAddress is indeed present.
Powered by vBulletin® Version 4.1.10 Copyright © 2012 vBulletin Solutions, Inc. All rights reserved.