manihiki
manihiki

Reputation: 682

How to correctly implement multiple views with UI Router in Angular?

I'm trying to implement a site with two main content 'panes' (imagine two columns each half the width of the page). The panes should be able to change independent of each other and have their own controllers and be able to pass data between each other (so the user can navigate through a bunch of pages on the left pane while the right pane stays the same without reloading and vice versa, and a change in the left pane can update data showing up in the right pane).

I've looked through a bunch of examples/tutorials on UI Router but can't seem to find a good example of how to implement what I'm trying to do. All of them seem to show either just examples for single nested views (so a single view within a larger view) or show multiple views but not how to change the views independent of each other.

I'd like to do this with a single <div ui-view></div> in the index.html file (as opposed to multiple ui-views) so that I can have everything happening within the single parent ui-view and not in the index.html file.

Right now I have something like the following js file:

config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
      $urlRouterProvider.otherwise('/home');
      $stateProvider
      .state('home', {
            url: '/home',
            views: {
                '': { templateUrl: 'views/home.html' },
                'left@home': { 
                  templateUrl: 'views/charting/chartHome.html',
                },
                'right@home': { 
                    templateUrl: 'views/view1.html',
                    controller: 'View1Ctrl'
                }
            }

        });
    }]);

and the following HTML for home.html:

<div>
    <h1>This is home</h1>
</div>
<div ui-view='left'>
</div>
<div ui-view='right'>
</div>

Can anyone help with this? Or is this the wrong way to be thinking about the site? If so what should I be doing?

Thanks!

Upvotes: 1

Views: 2592

Answers (1)

AWolf
AWolf

Reputation: 8990

This is pretty complicated to solve with ui-router.

I've created this fiddle to give ui-router nested states a try. It works but it is gettting ugly quickly.

It works like this: home.main.left route changes only the left view and uses the right view from home.main. It would be better to have both view states independent from each other but I'm not sure how to do that with ui-router.

I think it would be better to use ui-router to do the navigation of the left part and use a custom directive for the right part (or the other way round). To communicate to the directive you can use $emit/$broadcast.

Changing the route of the left part is also possible from the directive with links ui-sref or with $state.go(...) method.

Please have a look at the demo below or in this jsfiddle.

angular.module('demoApp', ['ui.router'])
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
      $urlRouterProvider.otherwise('/home');
      $stateProvider
      .state('home', {
          templateUrl: 'views/home.html',
          abstract: true
      })
      .state('home.main', {
            url: '/home',
            templateUrl: 'views/charting/chartHome.html',
          	controller: 'LeftCtrl'
        })
      .state('home.left', {
            template: 'home.left <a href="#" ui-sref="home.left1">left1 change</a><br/>{{hello}}',
          controller: 'LeftCtrl'
          
        })
      .state('home.left1', {
            template: 'home.left1 <a href="#" ui-sref="home.left2">left2 change</a>'
        })
      .state('home.left2', {
            template: 'home.left2 <a href="#" ng-click="triggerDirective()">change directive</a>',
          controller: function($scope) {
          	$scope.triggerDirective = function() {
            	console.log('do directive action');
                $scope.$emit('rightContent:changeMsg', 'new content');
                // emit to rootscope because rightcontent is not a child of leftcontent
            };
          }
        })
      
      
    }])
.directive('rightContent', function() {
	return {
    	restrict: 'EA',
        template: 'Some static content or other stuff from directive. <strong>{{message}}</strong>',
        controller: function($scope, $rootScope) {
            $scope.message = 'hello from directive.';
        	$rootScope.$on('rightContent:changeMsg', function(evt, message) {
                console.log(message);
            	$scope.message = message;
            });
        }
    }
})
.controller('LeftCtrl', function($scope){
    
    $scope.hello = 'hello from left';
})
.controller('appController', function($scope) {
});
.left {
    float: left;
    width: 50%;
    height: 200px;
    background: lightgreen;
}


.right {
    float: right;
    width: 50%;
    height: 200px;
    background: lightgray;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.4/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.15/angular-ui-router.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>

<div ng-app="demoApp" ng-controller="appController">
    <script type="text/ng-template" id="views/home.html">
        <div>
            <h1>This is home</h1>
        </div>
        <div class="wrapper">
            <div ui-view="" class="left">
            </div>
            <div class="right">
                <right-content></right-content>
            </div>
            <a href="#" ui-sref="home.main">home</a>
        </div>
    </script>
    <script type="text/ng-template" id="views/charting/chartHome.html">
        left {{hello}}
        <a href="#" ui-sref="home.left">left change</a>
    </script>
    <script type="text/ng-template" id="views/view1.html">
        right {{hello}}
    </script>
    
    <div ui-view=""></div>
</div>

Upvotes: 1

Related Questions