So this thing we’re building is a bit of a mash up of different design paradigms. Not since the X-files was (originally) on the air have we seen such an alien-human hybrid. It’s mostly a single page app, but some sections just don’t fit (the sitemap and news sections, in particular). They need their own, separate pages, reached via the traditional request-response route.
Which is which, though? I’d say the regular, old site method is the ‘human’. It’s old, probably on its way out, but still holds most of the power across the landscape. That makes Angular the alien- fast, strong, looking to first integrate with an unsuspecting population before completely enslaving it. No server will survive the coming apocalypse!
Anyway, we needed to be able to link from an external page (the footer of the News section, for instance) back to the main app (which uses Angular routing). Easy enough- it’s a simple link tag with the ‘target=_self’ attribute to make sure the server is contacted. But another wrinkle appears! On the main app, there is a section with multiple tabs. Different content is hidden behind each tab with an ng-if switch. Click a tab, switch the content.
How to get the proper tab content initialized when popping into the app from an external source? We found a way, though it’s not pretty. If the guys at Google saw what we did, they’d probably never stop vomiting. But the more I work with web development, the more that seems to be the case. The blog posts and tutorials all have this beautiful, clean, elegant code applied to clearly defined use cases.
But the real web is murkier. There are specs that can’t be changed (or you don’t have the authority to change them). People higher up the chain want things done a certain way, and sometimes it’s your job to just make it work. So I’m trying to stop worrying so much about what other (more skilled) people would think if they read my code, and just making it work (though always striving for that elusive, elegant, efficient solution).
So how did we solve the issue? Well- using the traditional client-server communication system, you can pass along a querystring in the url (anything after a ‘?’ character in your href string). When you ‘jump into’ an Angular app, it will wipe that out (via the ‘otherwise’ route, most likely, which ensures the proper view as a default). However, there is a hook in Angular called $routeChangeSuccess. When the route changes, this callback fires. So, in the main controller for the app, we initialize a variable: var aboutTab = location.search
This will grab that querystring (the location object’s search property) off the url. Because it’s done before the route officially takes over and redirects us to ‘/’, whatever was passed via the querystring gets saved before getting wiped out by Angular. Then, within the $routeChangeSuccess callback, you can use this variable to set the proper view on your tabs section.
It’s a little more complicated than that- the tab change function has to be inside a window.ready function, and if your co-worker decided to put spaces in the ng-if variables that change the tabs, you’ll also have to do a little string manipulation. Also, if you have other sections within your app (like the main footer) that control these tabs, you’ll have to store both the data and methods in a service. One final caveat- it’s a good idea to completely clear the aboutTab variable when you’re done with it (a simple aboutTab = null will work nicely). We put a hook on the tab change function that would also scroll the page to the tabs section, but if you don’t clear the variable, it can cause your screen to jump to the tabs section on other, unrelated route changes.
As an added bonus- once the ‘otherwise’ route (that redirects to ‘/’) takes over, it clears the url. So you’re not left with a weird looking ‘?tabhere’ appended to the url. It does its business and goes away.
If anyone actually reads this, feel free to let me know why this is a terrible idea and why it’s on the short list to be banned at the next Geneva Convention. But also let me know a better way to do it. And please, not the usual advice we’ve all seen on a certain developer help site: ‘You’re doing it all wrong if you need to use a trick like this- just redesign the entire project’. This is sometimes not an option.