[JavaScript] thoughts on supporting angularjs and its use of parameters named $foo


#1

So Java and JavaScript allows identifiers to start with $. $ is also the magic function in jquery (so we have to rename it jq in kotlin). However we can't do the same in Kotlin as $ is used to indicate a field.

There’s a popular JavaScript library from Google called angularjs which provides a really nice client side template mechanism with bidirectional binding between a model and the web browser UI. Its really cool; most of your app can just be HTML with a few special attributes and CSS; then a little bit of JS code for the controller. Using Kotlin to write controllers; and using angularjs + HTML / CSS would be a nice combination for writng web applications.

However angularjs uses parameter names beginning with $ as a naming convention for dependency injection of scopes, resources, location etc.

So we can’t use a parameter called $scope (the default parameter in an angularjs controller), though we can `` escape it…

fun MyController(`$scope`: JsObject) {

  `$scope`.foo = "hey"

}

This works and creates valid JS (I hacked up a little test case to check it worked), but its kinda ugly. Having $scope is noisy enough but then having to wrap the whole identifier in `` makes the JS look a bit neater :)

I wondered if folks had any ideas on what we could do to help the JS side of things a little. Maybe we could have a compiler plugin so that anything annotated with inject would automatically get swizzled to rename parameter names to prefix them with $ in the generated JS code?

``

import kotlin.angularjs.*

fun controller MyController(inject scope: JsObject) {
  scope.foo = “hey”
  // scope will be called $scope in the JS code
}

anyone got any brighter ideas? I did wonder about using the js.native annotation but that doesn’t seem to work as a way of renaming parameters.


#2

I have a similar issue. I wrote a JSON DSL for use in the MongoDB API. The problem is that all operators in MongoDB's query "language" are prefixed with $. Currently this is what I have:

val aggr = collection.aggregate {
    "$group" _ {
        "_id" _ null
        "average" _ {
            "$avg" _ "$value"
        }
    }
}

Obviously the problem is that $ is the start of a template expression in Kotlin, so needs to be escaped. My first thought was to define some global vals and use them instead of Strings (e.g. public val $group : String = "$group"), but that can't work either, because of the same reason James described. So I need to choose between "$group" and `$group`. The latter is not that bad, but it interacts badly with auto-complete (I guess that can be fixed in future Kotlin/IntelliJ versions) and "$group" is easier to type.

Some ideas/feature requests:

  • Assuming a $group variable in scope, invoking auto-complete on $g should result in $group (currently the result is $group, without the back-quotes = syntax error).
  • Typing should behave like typing ", that is, it needs to output a matching closing and whatever you type next should go in between, etc.
  • An annotation could be introduced that does for string templates what @NonNls does for i18n strings. That is, when that annotation is used on a string parameter, template processing will be disabled for that parameter and no escaping will be necessary. This also needs to work for the implicit parameter of extension functions. Examples (assumes the annotation is called “NonTemplate”):

fun foo([NonTemplate] id : String) // foo("$group") should work [NonTemplate] fun String.foo() // "$group".foo() should work


#3

An annotation will work


#4

If you define your global val gorup to hold a string "$group", it will work as you expect.

``

val group = “$group”

val whatever = “$group” // the values is “$group”


#5

Works great, thanks!