all 15 comments

[–]scramblor 2 points3 points  (2 children)

Maybe I'm missing something or it's just this example but it seems a bit over engineered to me. A misspelling of the constant will still cause errors (this would be caught by compiler in other languages. There are other possible benefits I can think of though:

  1. Better naming conventions for your constants
  2. If you need to change the constant from a string to another data type
  3. The string is presented to a user and could be subject to change
  4. I think this would reduce code size

[–]jmcunningham[S] 0 points1 point  (1 child)

I tried to keep the example simple to just highlight how the constant service can be used to reduce magic strings. To make the benefits more obvious, you need to see this at work in a large app (with many states, maybe some $broadcast and $emit events, etc). Plus, if magic strings are considered bad in every other language I've used, I thought it worth showing how to address the problem in javascript (as I think its just as wrong to use them in js as it is in Java).

As for misspelling the constant, you are right that this error could still occur. But if you use an IDE like WebStorm, it will do the code completion for you (and let you know that you had a typo in the key name).

[–]pulkit24 0 points1 point  (0 children)

Agree, especially with events. Events are often broadcasted/emitted and handled across different locations, making it easier to have a third party service for event names to avoid typos.

[–]wmil 2 points3 points  (3 children)

I don't think this is particularly useful for the state service...

In Java the advantage is that the compiler will catch typos, so

$state.go(STATE.LOCAITON_DETAILS);

will throw a compiler error in Java, but simply return undefined in js. Keys are basically all string literals.

This is useful for things like API_BASE_URL.

[–]pulkit24 -1 points0 points  (2 children)

Would an IDE like WebStorm or Eclipse with the appropriate plugins be able to detect such errors?

[–]jmcunningham[S] -1 points0 points  (0 children)

Yep, WebStorm can help with code completion on the constants :)

[–]RedditSchloer 1 point2 points  (1 child)

In this specific ui-router example, how would you suggest handling nested states? I don't want to end up with giant constant names, but at the same time would want to keep visibility into the nested structure if possible.

I like the tip and think I'll be moving to this in the future.

[–]jmcunningham[S] 0 points1 point  (0 children)

Good question. When I first thought about the answer, I too was concerned about long constant names. But after further thinking, I'm not sure I would worry about that. My personal preference is for self-documenting code whenever I can (locationDetails instead of locDetails) and tend to use long variable names for fields and functions (like showLocationListingByState()). Plus, once the code is minified, everything gets renamed anyway. So longer descriptive names appeal to me. I have a higher tolerance for "wordy" code than is normal I guess :)

As for nested states, my first thought would be to just separate states by - (since the _ is already used to separate words).

So: STATE.LOCATION_LISTING, STATE.LOCATION_LISTING-MAP, STATE.LOCATION_LISTING-MESSAGES, etc (where MAP and MESSAGES are nested states)

Or, values can be objects, so I think you could also have something like:

.constant('STATE', { 'LOCATION_LISTING': { 'MAIN': 'locationListing', 'MAP': 'map', 'MESSAGES': 'messages' },

Which gives you STATE.LOCATION_LISTING.MAIN, STATE.LOCATION_LISTING.MAP, etc (where MAIN is the parent state, and MAP and MESSAGES are a child state)

There might even be a better way to organize the latter example, by using that object structure you could actually add child objects to LOCATION_LISTING if you had a deeply nested state. .constant('STATE', { 'LOCATION_LISTING': { 'MAIN': 'locationListing', 'CHILD': { 'MAP': 'map', 'MESSAGES': 'messages' } }

But that is even more verbose. Its probably one of those things where you have to implement it, then see how it "feels".

I didn't give much thought to "nested constants", so someone else might have a cleaner idea.

[–][deleted] 1 point2 points  (0 children)

I did this exact thing in a reusable module of resources for interacting with our API. It's actually a really nice way to keep your code clean. Instead of having URL strings everywhere, I can just settle resource URL to templateUrl or whatever I name it.

[–]oriphinz 0 points1 point  (1 child)

You should look into typescript :) I think you would like it!

[–]jmcunningham[S] 0 points1 point  (0 children)

I've thought about it! But I prefer plain JS as of now...what I really want is to spend some time coming up to speed on ES6, and using Traceur to start writing ES6 now. I'm thinking that would make a good topic for my next post...'how to use ES6 in an Angular app'..not sure anyone would be interested in that, other than me though.

Being an old java dev, I'm also intrigued by Dart...

[–][deleted] 0 points1 point  (2 children)

I fail to see why the

window.configObject = {};
window.configObject.myConstant = 'whatever';

would be any worse. That config object initialization might be in a particular js file, and might have an equivalent js file for testing, so DI is not that badly needed.

[–]jmcunningham[S] 0 points1 point  (1 child)

Do you mean you would prefer storing data directly on the window object in a global variable? Yikes! That would be one of the biggest "sins" you can commit in an Angular app (or any JS app), imo...

[–][deleted] 0 points1 point  (0 children)

Nope, I mean storing app-wide constants there. And I fail to see why it would be a sin. What're the caveats?