Search code examples
angularjsangular-ui-routerbrowserify

Modular Angular app using Angular UI Router and Browserify


I've never used Angular UI Router before but I want to build an application that has nested views so it looks like the most sensible choice. However. I just can't get my head around it. My application is modular so I have an element on my page that I want the other modules, with their view templates, to load into.

Application wireframe

Then when some action is taken inside one of the nested views, say a button click, I would like the state to change so that module to becomes the only one inside the main view, and for the URL to change:

Application wireframe - with state change

I'm writing in CoffeeScript and using Browserify to tie the app together, so all the modules are in separate files and required in. This is where I've got so far but it's not working and I can't figure it out.

app.coffee

require...
require...
require...

app = angular.module("darrylsnow", [
    "ngAnimate"
    "ui.router"
    "submodule1"
    "submodule2"
    "templates"
]).config [
    "$stateProvider"
    "$urlRouterProvider"
    "$locationProvider"
    ($stateProvider, $urlRouterProvider, $locationProvider) ->

        $urlRouterProvider
            .otherwise "/"

        $stateProvider
            .state "main",
                abstract: true  # because the main module requires the submodules
                url: "/"

        $locationProvider.html5Mode true
]

submodule1.coffee

submodule1 = angular.module("submodule1", [
    "ui.router"
]).config [
    "$stateProvider"
    "$urlRouterProvider"
    "$routeProvider"
    ($stateProvider, $urlRouterProvider, $routeProvider) ->

        $stateProvider
            .state "main.submodule1",
                url: ""
                templateUrl: "submodule1.html"
            .state "main.submodule1-expanded",
                url: "/submodule1" # template shouldn't change

]

submodule2.coffee

submodule2 = angular.module("submodule2", [
    "ui.router"
]).config [
    "$stateProvider"
    "$urlRouterProvider"
    "$routeProvider"
    ($stateProvider, $urlRouterProvider, $routeProvider) ->

        $stateProvider
            .state "main.submodule2",
                url: ""
                templateUrl: "submodule2.html"
            .state "main.submodule2-expanded",
                url: "/submodule2" # template shouldn't change

]

Is it even possible to have child states in different modules? If not how would you recommend I do it? Thanks.


Solution

  • There is a working example, where I tried to show how to put angular, ui-router and coffee together. While I am not 100% sure what exactly you were trying to achieve ... you can find some answers and inspiration there.

    Firstly the (simplified) index.html

      <head> 
        ...
        <script src="app.js"></script>
        <script src="submodule1.js"></script> 
        <script src="submodule2.js"></script>     
      </head>
    
      <body>
       <ul>    
        <a ui-sref="main.submodule1.expanded">main.submodule1.expanded</a>
        <a ui-sref="main.submodule2({id:22})">main.submodule2</a>
        <a ui-sref="main.submodule2-expanded({id:22})">main.submodule2-expanded</a>
        <div ui-view=""></div>
      </body>
    

    Now, this would be the app.coffee, where the most important part is the template. That will allow each child to inject its view into this unnamed view template. The other option would be to use absolutely named views, but this keeps it simple:

    app = angular.module("darrylsnow", [
        "ui.router"
        "submodule1"
        "submodule2"
    ]).config [
        "$stateProvider"
        "$urlRouterProvider"
        "$locationProvider"
        ($stateProvider, $urlRouterProvider, $locationProvider) ->
    
            $stateProvider
                .state "main",
                    template: "<div ui-view />"
                    abstract: true  # because the main module requires the submodules
                    url: "/" 
         ...
    

    The other files represents really different modules.

    The example of submodule1.coffeee shows that even here we are using nesting (the main.submodule1.expanded is child of main.submodule1):

    submodule1 = angular.module("submodule1", [
        "ui.router"
    ]).config [
        "$stateProvider"
        "$urlRouterProvider"
        "$locationProvider"
        ($stateProvider, $urlRouterProvider, $locationProvider) ->
    
            $stateProvider
                .state "main.submodule1",
                    template: "<div ui-view />"
                    abstract: true
                .state "main.submodule1.expanded",
                    url: "/submodule1" # template shouldn't change
                    templateUrl: "submodule1.html"
                    controller: 'Some1Ctrl'
    
    ] 
    submodule1.controller 'Some1Ctrl', [  
        "$scope"
        "$stateParams"
        "$state"
        ($scope, $stateParams, $state) ->
            $scope.params = $stateParams;
            $scope.state = $state.current;
    ]
    

    As a different approach we can use siblings as the submodule2.coffee shows:

    submodule2 = angular.module("submodule2", [
        "ui.router"
    ]).config [
        "$stateProvider"
        "$urlRouterProvider"
        "$locationProvider"
        ($stateProvider, $urlRouterProvider, $locationProvider) ->
    
            $stateProvider
                .state "main.submodule2",
                    templateUrl: "submodule2.html"
                    controller: 'Some2Ctrl'
                .state "main.submodule2-expanded",
                    url: "/submodule2/{id}" # template shouldn't change
                    templateUrl: "submodule2.html"
                    controller: 'Some2Ctrl'
           ...
    

    Well how that all fits together is the best to observe in this plunker