Is there any better way to write this Kotlin-javascript function?

This is some javascript code, which is a directive in angularjs:

todomvc.directive('todoFocus', function todoFocus($timeout) {
    return function (scope, elem, attrs) {
        scope.$watch(attrs.todoFocus, function (newVal) {
            if (newVal) {
                $timeout(function () {
                    elem[0].focus();
                }, 0, false);
            }
        });
    };
});

And following is my Kotlin code:

val xxx = {(timeout: Timeout) ->
    {(scope: BaseScope, elem: Elem, attrs: Attrs) ->
        scope.`$watch`(attrs.todoFocus, { (newVal: Any) ->
            if(newVal as Boolean) {
                timeout({ elem[0].focus() }, 0, false);
            }
        })
    }
}

I think the kotlin-js version is less readable compared to the javascript one.

Is there any better way to write it? And if kotlin provide something like the javascript, that we can use fun(...) {} to define function literals just as javascript?

Hi! At first, you can omit type declarations if they are clear from the context (and therefore can be inferred). Like when you invoke

fun test(): (Int) -> Int {   fun inner(i: Int) = i   return ::inner }

Which version of Kotlin are you using? My kotlin plugin doesn't allow me to write: `::myfun`

And I can't ignore types since the `directive(...)` method is very flexiable, I often declare it as `Any` or something.

So in my own function, I have to declare the types explicitly.

This feature is not supported now in js-backend.

Can you show your declarations for todomvc.directive and scope.$watch

Kotlin code:

  fun directive(name: String, def: (vararg Any)->Any): Unit

  fun $watch(exp: Any, todo: (vararg Any) -> Unit, deepWatch: Boolean)
  fun $watch(exp: Any, todo: (vararg Any) -> Unit)

I think you have wrong declarations.

For $watch it should be look like:

native("$watch") fun watch(watchExpression: String): () -> Unit = js.noImpl

native("$watch")
fun watch(watchExpression: String, listener: String): () -> Unit = js.noImpl
native("$watch")
fun watch(watchExpression: String, listener: String, objectEquality: Boolean): () -> Unit = js.noImpl

native("$watch")
fun watch<T>(watchExpression: String, listener: (newValue: T, oldValue: T, scope: Scope) -> Any): () -> Unit = js.noImpl
native("$watch")
fun watch<T>(watchExpression: String, listener: (newValue: T, oldValue: T, scope: Scope) -> Any, objectEquality: Boolean): () -> Unit = js.noImpl

native("$watch")
fun watch(watchExpression: (scope: Scope) -> Any, listener: String): () -> Unit = js.noImpl
native("$watch")
fun watch(watchExpression: (scope: Scope) -> Any, listener: String, objectEquality: Boolean): () -> Unit = js.noImpl

native("$watch")
fun watch<T>(watchExpression: (scope: Scope) -> Any, listener: (newValue: T, oldValue: T, scope: Scope) -> Any): () -> Unit = js.noImpl
native("$watch")
fun watch<T>(watchExpression: (scope: Scope) -> Any, listener: (newValue: T, oldValue: T, scope: Scope) -> Any, objectEquality: Boolean): () -> Unit = js.noImpl


For directive i wrote:

native fun directive(name: String, def: (Timeout)->Any): (scope: Scope, elem: Elem, attrs: Attrs) -> Unit = js.noImpl

But I'm sure that `def` has the wrong type. Unfortunately I am not familiar with AngularJS for fix it.

And now you can write:

  directive("todoFocus") { (timeout: Timeout) ->   {(scope: Scope, elem: Elem, attrs: Attrs) ->            watch<Boolean>(attrs.todoFocus) { (newVal, oldVal, scope) ->            if(newVal) {                    timeout({ elem[0].focus() }, 0, false);            }            }   }   }

Next, you can add helper function postLink like:

inline fun postLink(f: (scope: Scope, elem: Elem, attrs: Attrs) -> Unit) = f

then:

  directive("string") { (timeout: Timeout) ->   postLink {(scope, elem, attrs) ->  // <-------------------------------------------- without type declaration here            watch<Boolean>(attrs.todoFocus) { (newVal, oldVal, scope) ->            if(newVal) {                    timeout({ elem[0].focus() }, 0, false);            }            }   }

But now it add unnecessary function call in generated js.

Thanks for you detailed answer, yours are more accuracy than mine.

But methods like “directive”, we can give it a specific type to the parameters, since there are ofter many directives in a project, and each has a different types. So I use “vararg” in the declaration, and specify the types when I define a directive.

Then the compiler can not help you detect type errors.

P.S. I’m a little updated prev message – made watch declaration better…

Usefull resources: http://code.google.com/p/closure-compiler/source/browse/contrib/externs/angular.js http://code.google.com/p/closure-compiler/source/browse/contrib/externs/angular.jshttps://github.com/borisyankov/DefinitelyTyped/tree/master/angularjs

It looks much better now, thank you again!

And I still hope Kotlin providing better syntax to allow me returning a function easily.

I forgot, also you can write so:

``

watch<Boolean>(attrs.todoFocus) {

}

I think such example would look difficult/ugly in almost any language.

Thank you, even better :)

Agree. And the javascript version may be the most readable one.

I think you have written wrong syntax. If you want to improve you skills in Angular then i suggest you to do AngularJS Course