4
\$\begingroup\$

On my site I have a navbar component that I want to customize for each and every ng-view I end up loading. Currently I'm doing this as follows. I have a NavCtrl for the navbar itself and my ng-view directive sits outside the scope of this controller. And I use a navbar service to change/override functionality in the navbar e.g each of my views need to override the click handler for a save button my navbar. The NavbarService has hooks to set the save function. And in the NavCtrl the $scope.save = NavbarService.save.

var app = angular.module('myApp', ['ngRoute', 'ngResource']);

app.config(function($routeProvider) {
  $routeProvider.when('/world', {templateUrl : 'world.html', controller : 'WorldCtrl'}).otherwise({templateUrl : 'hello.html', controller : 'HelloCtrl'});
});

app.service('NavbarService', function() {
  var message = 'Save button not clicked yet',
      saveFunction = function() {
    this.setMessage('Default save called');
  };
  
  this.save = function() {
    _saveFunction();
  };
  
  this.setSaveFunction = function(funct) {
    _saveFunction = funct;
  };
  
  this.setMessage = function(newMessage) {
    message = newMessage;
  };
  
  this.getMessage = function() {
    return message;
  }
});

app.controller('NavCtrl', function($scope, $location, NavbarService) {
  $scope.message = NavbarService.getMessage();
  $scope.save = NavbarService.save;
  $scope.world = function() {
    $location.path('/world');
  };
  
  $scope.hello = function() {
    $location.path('/hello');
  };
  
  $scope.$watch(NavbarService.getMessage, function(newValue) {
    $scope.message = newValue;
  });
});

app.controller('HelloCtrl', function($scope, NavbarService) {
  $scope.init = function() {
    NavbarService.setSaveFunction(function() {
      NavbarService.setMessage('Save method called from the HelloCtrl');
    });
  };
});

app.controller('WorldCtrl', function($scope, NavbarService) {
  $scope.init = function() {
    NavbarService.setSaveFunction(function() {
      NavbarService.setMessage('Save method called from the WorldCtrl');
    });
  };
});
<html lang="en">

<head>
  <title>My App</title>
</head>

<body ng-app="myApp">
  <nav ng-controller="NavCtrl">
    <button ng-click="save()">Save</button>
    <button ng-click="world()">Go to world</button>
    <button ng-click="hello()">Go to hello</button>
    <pre>{{message}}</pre>
  </nav>

  <div ng-view onload="init()"></div>

  <script type="text/ng-template" id="hello.html">
    <h2>Active view is Hello</h2>
  </script>

  <script type="text/ng-template" id="world.html">
    <h2>Active view is World</h2>
  </script>

  <script src="https://code.jquery.com/jquery-2.1.4.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular-route.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular-resource.js"></script>
</body>

</html>

I'm wondering if I'm making this too complicated. I think the same thing can be achieved by just nesting the ng-view directive within the NavCtrl's scope. That way I can override $scope.save in each view controller.

But most the documentation states that services are the preferred way to share resources across controllers. Is one way better than the other? Why?

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.