1

I'm trying to refactor our current layout to add in a dynamic show/hide section above the header on our page. We are using Angularjs 1.4.2 with ui-router and currently we are using separate route files, although we have a main route. The main.html section of the screen, up to now, was the only section with the dynamic content. In order to get my new route working, I'm having to add it and main to each of the existing routes.

My question is, would a better design be something along this line of a single parent route to handle a resolve, with nested states for the dynamic main content and a new view for my new route and content? As the application grows, do you still continue to put the new routes into the parent route or is there a better way to organize it like we were doing with individual route files or a combination of both?

This is what I'm trying, but it's not working yet, as I'm getting a blank page, but the design for future growth with the application is what I'm trying to get right here:

(function () {
    'use strict';

    angular
        .module('myApp')
        .config(config);

    config.$inject = ['$stateProvider'];
    /* @ngInject */
    function config($stateProvider) {
        $stateProvider
            .state('root', {
                template: '<ui-view></ui-view>',
                abstract: true,
                resolve:{
                    myLoader:  ['myLoader', function(myLoader){
                        // $http returns a promise for the url data
                        return myLoader.load();
                    }]
                }
            }
            .state('main'), {
                url: '/?param1&param2&param3&param4',
                templateUrl: 'app/routes/main/main.html',
                controller: 'MainCtrl',
                redirectTo: 'main'
            })  
            $stateProvider
            .state('basicsearch', {
                url: '/basic-search',
                templateUrl: 'app/routes/basicsearch/basicsearch.html',
                controller: 'searchQuickCtrl'
            })
            $stateProvider
            .state('advancedsearch', {
                url: '/advaned-search',
                templateUrl: 'app/routes/advancedsearch/advancedsearch.html',
                controller: 'advancedSearchkCtrl'
            })
            $stateProvider
            .state('anothersearch', {
                url: '/another-search',
                templateUrl: 'app/routes/anothersearch/anothersearch.html',
                controller: 'anotherSearchCtrl'
            })
            .state('myChange', {
                url: '/myChange?param5&param6&param7&param8',
                views: {
                     "myChangeView": {
                         templateUrl: '/app/routes/myChange/myChange.html',
                         controller: 'myChangeCtrl'
                     }
                }

            }); 
    }
})();

Here is a basic layout of what we have: enter image description here

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
James Drinkard
  • 15,342
  • 16
  • 114
  • 137
  • Could you create a plunker? It is not clear what is NOT working for you. UI-Router is not so complicated at the end... – Radim Köhler Nov 07 '15 at 15:39
  • Maybe not for you, but I'm new to it! Let me try. – James Drinkard Nov 07 '15 at 15:43
  • I can assist, but not sure which direction you want to go... – Radim Köhler Nov 07 '15 at 15:43
  • I'm attempting to refactor the routing to allow for a new view, outside of the main.html area where all the dynamic content existing for the most part. The way it is, its not very flexible to add in new views. – James Drinkard Nov 07 '15 at 15:59
  • Look, I did my best to extract your issue in some working plunker. It is described in my answer. Observe it and even change to show what is not working for you. Hope that will give you some hints and help when coming to mighty UI-Router ;) – Radim Köhler Nov 07 '15 at 16:05

1 Answers1

2

I am not sure about the issue. But I created working plunker, to show you how we can use state nesting and resolve.

So this is our parent controller for root state and the factory used in resolve

.factory('myLoader', function(){
  return {
    load: function () {return [1,2] }
  };
})
.controller('ParenCtrl', ['$scope', 'myLoader', function ($scope, myLoader) {
  $scope.myLoader = myLoader;
}])
.controller('MainCtrl', ['$scope', 'myLoader', function ($scope, myLoader) {}])
.controller('searchQuickCtrl', ['$scope', 'myLoader', function ($scope, myLoader) {}])
.controller('advancedSearchkCtrl', ['$scope', 'myLoader', function ($scope, myLoader) {}])
.controller('anotherSearchCtrl', ['$scope', function ($scope) {}])

Next, we will use controller for abstract root state, to assign result into scope:

.state('root', {
    template: '<div ui-view></div>',
    abstract: true,
    controller: 'ParenCtrl',
    resolve:{
        myLoader:  ['myLoader', function(myLoader){
            // $http returns a promise for the url data
            return myLoader.load();
        }]
    }
})

And all states will use that as their parent, and inherit the scope:

.state('main', {
    parent: 'root',
    url: '/?param1&param2&param3&param4',
    templateUrl: 'app/routes/main/main.html',
    controller: 'MainCtrl',
    //redirectTo: 'main'
})  

.state('basicsearch', {
    url: '/basic-search',
    templateUrl: 'app/routes/basicsearch/basicsearch.html',
    parent: 'root',
    controller: 'searchQuickCtrl'
})

.state('advancedsearch', {
    url: '/advaned-search',
    templateUrl: 'app/routes/advancedsearch/advancedsearch.html',
    parent: 'root',
    controller: 'advancedSearchkCtrl'
})

.state('anothersearch', {
    url: '/another-search',
    parent: 'root',
    templateUrl: 'app/routes/anothersearch/anothersearch.html',
    controller: 'anotherSearchCtrl'
})

And properly use it inside of this view:

<div >
  <h3>current state name: <var>{{$state.current.name}}</var></h3>

  <h4>resolved in parent</h4>
  <pre>{{myLoader | json }}</pre>

  <h5>params</h5>
  <pre>{{$stateParams | json}}</pre>
  <h5>state</h5>
  <pre>{{$state.current | json}}</pre>

 </div>

while all these controller do not use that resolved value

.controller('MainCtrl', ['$scope', 'myLoader', function ($scope, myLoader) {}])
.controller('searchQuickCtrl', ['$scope', 'myLoader', function ($scope, myLoader) {}])
.controller('advancedSearchkCtrl', ['$scope', 'myLoader', function ($scope, myLoader) {}])
.controller('anotherSearchCtrl', ['$scope', function ($scope) {}])

So, each controller can be provided with stuff resolved in parent (as parameter). That is shown above. But also, becuase parent already used that and assigned that to some $scope variable... all is alraeady in place.

Also check:

Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335