0

I have a component() which injects a nav. When I try to include the controller inside this component like so, I get an error.

inside nav.html

<nav class="navbar navbar-inverse navbar-fixed-top">
  <div class="container">
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="navbar-brand" href="#">Demo</a>
    </div>
    <div id="navbar" class="collapse navbar-collapse" ng-controller="MainMenuController">
      <ul class="nav navbar-nav">
        <li ng-class="{ active: isActive('') }"><a href="./">home</a></li>
        <li ng-class="{ active: isActive('/skus') }"><a href="sku.html">sku</a></li>
        <li ng-class="{ active: isActive('/phones') }"><a href="phone.html">phone</a></li>
      </ul>
    </div><!--/.nav-collapse -->
  </div>
</nav>


inside component.js

angular.
module('mainMenu').
component('mainMenu', {
  templateUrl: 'app/core/nav/nav.html',
  controller: 'MainMenuController', ['$scope', '$location', 
    function NavController($scope, $location) {
        $scope.isActive = function (viewLocation) { 
          var p1 = $location.path();
          var p2 = '/' + p1.split("/")[1]; // split string from '/';
          if(p2=='/undefined') p2 = '';
          return viewLocation === p2;
        }
    }
  ]
});

But if I write a separate controller like this everything works fine. What am I doing wrong with component() and should I not be including the controller in component() for best practice?

angular.
module('mainMenu').
component('mainMenu', {
  templateUrl: 'app/core/nav/nav.html',
});


angular.
module('mainMenu').
controller('MainMenuController', ['$scope', '$location', 
      function NavController($scope, $location) {
        //this.navs = Nav;
        $scope.isActive = function (viewLocation) {
          var p1 = $location.path();
          var p2 = '/' + p1.split("/")[1]; // split string from '/';
          if(p2=='/undefined') p2 = '';
          return viewLocation === p2;
        };
      }
]);


I changed my component to this

angular.
module('mainMenu').
component('mainMenu', {
  templateUrl: 'app/core/nav/nav.html',
  controller: ['$scope', '$location', 
    function MainMenuController($scope, $location) {
      //this.navs = Nav;
      $scope.isActive = function (viewLocation) {
        var p1 = $location.path();
        var p2 = '/' + p1.split("/")[1]; // split string from '/';
        if(p2=='/undefined') p2 = '';
        return viewLocation === p2;
      };
    }
  ]
});

getting error Error: [ng:areq] http://errors.angularjs.org/1.5.8/ng/areq?p0=MainMenuController&p1=not%20a%20function%2C%20got%20undefined N



Fix: By cleaning up the module and component titles and making them unique, removing ng-controller from the template; Neal Hamilton's answer below fixed my original question.

t q
  • 4,593
  • 8
  • 56
  • 91
  • 1
    Either you specify a controller name, or you specify a controller function, but not both. Remove `'MainMenuController', `. Also, please never, ever again ask a question just saying "I have an error". Post the exact and complete error message instead. – JB Nizet Oct 07 '16 at 16:45
  • 2
    "I get an error." **what error**?? – Claies Oct 07 '16 at 16:47
  • Changed my question with error output – t q Oct 07 '16 at 16:50
  • 1
    In your first example, you are naming your component to be the same as your module which is a no-no. Also, all the information you seek is documented in the [angular documentation for components](https://docs.angularjs.org/guide/component). – Anil Oct 07 '16 at 16:51
  • this **seems** like you are using `ng-controller = "MainMenuController"` inside your nav.html template, but you haven't posted that code so that's just a guess. If that is the case, however, that's not the right way to declare directives or components. You should ***never*** use `ng-controller` in a template. – Claies Oct 07 '16 at 17:11
  • @Claies thank you for the response. I got that reference from here `http://stackoverflow.com/questions/12295983/set-active-tab-style-with-angularjs` @Zymotik answer – t q Oct 07 '16 at 17:16
  • that answer you referenced in the comment isn't a component or a directive, so it's not even applicable here. I stand by my statement, it is incorrect to use `ng-controller` inside a directive or controller template, as the controller is supplied by the definition. – Claies Oct 07 '16 at 17:42
  • or, if I interpret this another way, that answer is showing a `div` that is *outside* the component/directive, but you seem to be wanting to use the controller that belongs to the component for it. This is still incorrect, as you shouldn't be sharing a controller between a component and something not the component. – Claies Oct 07 '16 at 17:49
  • it's still unclear what you are trying to accomplish either way, since you haven't provided a [mcve] that shows where the `ng-controller` is at, which is the only thing that could be generating this error. – Claies Oct 07 '16 at 17:50
  • @Claies I have updated my question to show the `nav.html` template. yes the `ng-controller` was inside there. Where would you recommend to place this? inside the parent index.html file in ``? – t q Oct 07 '16 at 18:03
  • 1
    so again, this latest update verifies my theory. You have an `ng-controller` reference inside the template. the controller is being supplied to the whole template, and then you are trying to **re-bind** the *same* controller to an element inside the template. It may work when you declare the controller outside the template, but it probably won't work the way you expect, as you actually have two instances of the same controller object. It definitely won't work at all if you only declare the controller as belonging to the component. – Claies Oct 07 '16 at 18:04
  • @Claies awesome, thank you! – t q Oct 07 '16 at 18:06
  • from what I can see based on that template, you don't even need `ng-controller` to be defined at all. – Claies Oct 07 '16 at 18:06

1 Answers1

5

this is my preference when adding controllers...

MainMenuController.$inject = ['$scope', '$location'];
function MainMenuController($scope, $location) {}

angular.module('menu').component('mainMenu', {
    controller: MainMenuController,
    controllerAs: 'MainMenuController',
    templateUrl: 'app/core/nav/nav.html'
});

the style you're trying to do with dependencies inline...

angular.module('menu').component('mainMenu', {
    controller: ['$scope', '$location', function($scope, $location) {}],
    controllerAs: 'MainMenuController',
    templateUrl: 'app/core/nav/nav.html'
});

Difference being that you had the ControllerAs String with the controller declaration. You should be using the controllerAs: "NameForController" property to name the controller.

Good Luck!

nham
  • 161
  • 5
  • when I used your first answer I still get an `Error: [ng:areq] http://errors.angularjs.org/1.5.8/ng/areq?p0=MainMenuController&p1=not%20a%20function%2C%20got%20MainMenuController N/` – t q Oct 07 '16 at 17:23
  • That error is indicating that you are passing a string "MainMenuController" and not a function to the controller property. – nham Oct 07 '16 at 17:36
  • but I have it set up exactly as yours. – t q Oct 07 '16 at 17:38
  • I think I forgot a comma after controllerAs: 'MainMenuController' , <-- – nham Oct 07 '16 at 17:41
  • I made a edit in my answer to include the comma that was missing, and I would be interested to know what happens now.. Thanks, and sorry for the mistake. – nham Oct 07 '16 at 17:42
  • I had the comma in mine – t q Oct 07 '16 at 17:43
  • 1
    That fiddle is working code like the one from my first example. hopefully that will help sort things out. – nham Oct 07 '16 at 17:50
  • thank you!! my module names needed cleaning as @AnilNatha pointed out – t q Oct 07 '16 at 18:19