Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have many C# enums, and some of them have flags enabled. For example:

[Flags]
public enum MyEnum
{
  item1 = 0x0000,
  item2 = 0x0008
}

I cloned this into JavaScript with something like this:

my.namespace.MyEnum = {
  ITEM1: "item1",
  ITEM2: "item2"
}

I am using a global WebApi converter to map enums to string, because I prefer to use the strings with the REST API:

config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new StringEnumConverter());

The problem is that if I create a property that uses this enum, it can't use the bitwise operations (i.e. my.namespace.MyEnum.ITEM1 | my.namespace.MyEnum.ITEM2) and get the desired result ("item1, item2").

Aside from removing the string converter, is there any proper way to implement this kind of DataContract + JS API for flags enum in JavaScript?

share|improve this question

3 Answers

why not just repeat the values from your asp.net code?

MyEnum = {
  ITEM1: 0x0000,
  ITEM2: 0x0008
}

alert(MyEnum.ITEM1 | MyEnum.ITEM2); // shows 8
share|improve this answer
The reason is that means you need to maintain the logic for the enums (the corresponding numbers) on the client JS as well, which is undesirable.. instead, using my method of the string, if the server decides to change its numbering scheme, the JS remains unaffected and oblivious, which is much better for maintenance. – automaton 2 days ago
@automaton: hmm. enumerations use numbers, hence the "num" part of the word. you can concat the tokens and search for memberships in the whole, but that's not really making anything easier. there's is no semantic or performance advantages to writing out "x.ITEM1" vs "item1", and in fact, "item1" is shorter, faster, and more readable in js. – dandavis 2 days ago
@dandavis: agreed, and that's why I mostly avoid enums and most other forms of string constants in JS. – Scott Sauyet 2 days ago
Well the advantage of x.ITEM1 over "item1" is that, again, if the server decides to change the name of "item1" enum, the API users won't notice. We can maintain the API without breaking by simply changing the string that x.ITEM1 represents. It's another shield against API changes, along with the fact we're using strings instead of the original numbers. – automaton 2 days ago
@automaton: But you are no more shielded from the server deciding to change the string "ITEM1". There is no strong typing in JS, and the fact that you can access this as x.ITEM1 is only a gloss on the more fundamental access as x['ITEM1']. So if you have some good reason to assume that the server is much more likely to change "item1" than "ITEM1", then you may have a reason. But if not, you aren't gaining anything in the Javascript. – Scott Sauyet 2 days ago

While I'm not a big fan either of enums in Javascript nor of such flag operators, I think this might be reasonably close to what you want:

[my.namespace.MyEnum.ITEM1, my.namespace.MyEnum.ITEM2].join(", ") //=> "item1, item2"

or

var join = function() {
    return Array.prototype.join.call(arguments, ", ");
};

join(my.namespace.MyEnum.ITEM1, my.namespace.MyEnum.ITEM2); //=> "item1, item2"
share|improve this answer
might as well just use [].toString(), the extra space in your custom method does little for us... – dandavis 2 days ago
@dandavis: You could, of course, but I would prefer to be more explicit than that. And the space was in the original. – Scott Sauyet 2 days ago

Here is another technique that fakes out some operator overloading. It's not one that I would actually recommend, but it's an interesting thought experiment, in any case:

var Enum = function(name) {return function() {return name;};};

var my = {}; my.namespace = {};
my.namespace.MyEnum = {
    ITEM1: Enum("item1"),
    ITEM2: Enum("item2")
};

var Σ = function() {
    var queue = [];
    var valueOf = Function.prototype.valueOf;
    Function.prototype.valueOf = function() {
        queue.push(this());
    };
    return function() {
        Function.prototype.valueOf = valueOf;
        return queue.join(", ");
    };
};

Σ()(my.namespace.MyEnum.ITEM1 | my.namespace.MyEnum.ITEM2); //=> "item1, item2"

It wouldn't help if you wanted to mix and match different operators, and although it might be possible to make something more complicated that would, I wouldn't bother, because even this is probably not something to use for real-world situations.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.