-
Notifications
You must be signed in to change notification settings - Fork 42
UIRouter: example how to set controller of a State? #45
Description
I'm new to this library, so hopefully this is a very easy question. I am using scalajs-angular version 0.5-SNAPSHOT and angular-ui-router version 0.2.15.
I am trying to implement the first example on the AngularUI Router tutorial, which is given in JavaScript. I have it working using scalajs-angular except for one part: the setting of the controllers on the state objects.
Update and Tentative Conclusion
I have, if not solved this, at least reached a work-around, posted in detail at the end. In brief, near as I can tell controllers must be registered in order for them to have scope injected, which is not possible with an anonymous function as in the JavaScript version. I could be totally wrong about this, and I invite correction.
End of Update. This Is My Original Questions:
In the JavaScript tutorial it looks like this:
.state('state1.list', {
url: "/list",
templateUrl: "partials/state1.list.html",
controller: function($scope) {
$scope.items = ["A", "List", "Of", "Items"];
}
})Looking at the companion object for State I see the factory apply() method has parameters for url and templateUrl, both of type String, and I set those no problem. I have failed, however, to set the controller member, which the State trait defines as type js.Any. Since in the JavaScript version, the value of controller is a function that takes a scope object and sets that object's items property, I tried setting controller to be a Scala function object:
state("state1.list", {
val s = State(
url = "/list",
templateUrl = "partials/state1_list.html"
)
s.controller = (scope: State1Scope) => scope.items = js.Array("A", "List", "Of", "Items")
s
})With State1Scope defined like this:
trait State1Scope extends Scope {
var items: js.Array[String] = js.native
}I also tried it with the type of State1Scope.items being a Scala Array rather than js.Array.
I also attempted to set the value of controller to be a JavaScript function, like this:
s.controller = new scalajs.js.Function1[State1Scope, Unit] {
override def apply(scope: State1Scope) { scope.items = js.Array[String]("A", "List", "Of", "Items") }
}Not only did that fail, but I also got a warning that Members of traits, classes and objects extending js.Any may only contain members that call js.native.
The error I am getting is in my browser console:
Error: [$injector:unpr] Unknown provider: scope$2Provider <- scope$2
http://errors.angularjs.org/1.4.1/$injector/unpr?p0=scope%242Provider%20%3C-<div ui-view="" class="ng-scope">cope%242
I have annotated my Config object with @injectable("StateConfig").
Other Things I Have Tried
Here are some other things I have tried, all unsuccessful:
I thought maybe of setting controller to be a Controller object like this:
s.controller = new Service with Controller[State1Scope] {
override def initialize() {
scope.items = js.Array[String]("A", "List", "Of", "Items")
}
}.asInstanceOf[js.Object]But that won't work because scope is never defined. (In the JavaScript version, the scope is passed as an argument to the function that is the value of the controller property. The analogous way in Scala would seem to be to make scope be an argument to the apply() method of a function object.)
Which led me to try this:
s.controller = new Service with Controller[State1Scope] {
private var scopeOption: Option[State1Scope] = None
override def scope = scopeOption match {
case None => throw new NoSuchElementException("scope unset")
case Some(sp) => sp
}
def apply(passedScope: State1Scope) { scopeOption = Some(passedScope) }
overide def initialize() {
scope.items = js.Array[String]("A", "List", "Of", "Items")
}
}.asInstanceOf[js.Object]That gave me a different error in the browser console: Error: [ng:areq] Argument 'fn' is not a function, got Object which sounds as if I'm going in the wrong direction.
I also have tried first defining the controller as a separate object. I copied the example Controller from from the scalajs-angular documentation under the heading Property Based Dependency Injection, changing its type annotation of Scope to my Scope sub-trait, but that failed to compile with the error:
[error] ... method scope_= overrides nothing
[error] override var scope: State1Scope = _
[error] ^
I hope I'm missing something really basic. I'll be happy to post more of my code if that will help. I think if I could see a working example that would be enough to get me unstuck. I looked at olivergg's scalajs-ionic-starttabs app but there are no instances of setting the controller of a State in the relevant file. I also looked for any tests in the scalajs-angular repository that might set the controller member of a State, but I failed to find any.
My sincere thanks and appreciation to anyone who can give me any guidance on this.
End of Original Question
Ultimately I gave up on trying to create the controllers as function literals within invocations of StateProvider.state(). Rather I defined them like this:
@injectable("State1Ctrl")
class State1Controller(scope: State1Scope) extends AbstractController[State1Scope](scope) {
scope.items = js.Array("A", "List", "Of", "Items")
}and also registered them in my app module:
module.controller[State1Controller]
module.controller[State2Controller]and then my invocation of StateProvider.state in my StateConfig looks like:
state("state1.list", State(
url = "/list",
views = Map("viewA" -> View("partials/state1_list.html", "State1Ctrl"))
)).The two arguments to the application of the View object are, respectively, the former value of the urlTemplate argument, and the name of the controller given in the @injectable annotation.
Finally, I had to update the corresponding ui-view attributes, setting their values to the keys of the Map value of the views argument to StateProvider.state():
<div ui-view="viewB"></div>So this Scala version does what the JavaScript example tutorial does, though it's built a bit differently with named controllers rather than anonymous functions. I am a long way from having a solid understanding of everything going on here, so if anyone feels like shedding light on this situation, I will be eager to learn all I can.