thank_you
thank_you

Reputation: 11107

How to instantiate ng-controller based on a condition

I asked this question but the specific question I'm asking has changed dramatically.

I have a piece of code:

  <div ng-attr-controller="{{pings || 'PingsCtrl as pings' }}">
    <h1 ng-click="pings.press()">asdf</h1>
  </div>

This code is injected into two html pages. One page already calls PingsCtrl. The other doesn't. I'm really trying to keep this code DRY and I only want to have one reference of the code above.

How can I write the code above to generate ng-controller if PingsCtrl hasn't already instantiated.

Here are the two html pages.

HTML

// First page
<html ng-app="coolApp">
  <div ng-controller="PingsCtrl as pings">
    <div ng-attr-controller="{{pings || 'PingsCtrl as pings' }}">
      <h1 ng-click="pings.press()">asdf</h1>
    </div>
  </div>
</html>

// Second page
<html ng-app="coolApp">
  <div ng-attr-controller="{{pings || 'PingsCtrl as pings' }}">
    <h1 ng-click="pings.press()">asdf</h1>
  </div>
</html>

Javascript is here:

angular.module('coolApp', [])

.controller('PingsCtrl', function() {
  var vm = this;

  vm.press = function() {alert(123)};
})

What's wrong and how do I fix this?

Upvotes: 17

Views: 1682

Answers (3)

Alexander Elgin
Alexander Elgin

Reputation: 6956

Please, check my solution to see how to share data between controllers

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

app.controller("aCtrl", function ($scope, PingList) {
  $scope.addPing = function() {
    PingList.add('Ping A');
  };
});

app.controller("bCtrl", function ($scope, PingList) {
  $scope.addPing = function() {
    PingList.add('Ping B');
  };
});

app.factory('PingList', function () {
  var pings = ['Ping1', 'Ping2'];

  return {
    add: function(ping) {
      pings.push(ping);
    },
    get: function () {
      return pings;
    }
  };
});

app.directive('pingList', function(PingList) {
  return {
    restrict: 'EA',
    link: function($scope) {
      $scope.pings = PingList.get();
      $scope.press = function(ping) {
        alert(ping);
      }
    },
    template: '<ul><li ng-repeat="ping in pings" ng-click="press(ping)">{{ping}}</li></ul>'
  };
});
a, li {
  cursor: pointer;
}

a {
  color: blue;
  text-decoration: underline;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>

<div ng-app="myApp">
  <div ng-controller="aCtrl" style="float: left">
    <a ng-click="addPing()">click to add A ping</a>
    <ping-list></ping-list>
  </div>
  <div ng-controller="bCtrl" style="float: right">
    <a ng-click="addPing()">click to add B ping</a>
    <ping-list></ping-list>
  </div>
  <div style="clear: both"></div>
</div>

Upvotes: 1

matthewdaniel
matthewdaniel

Reputation: 1970

I do have a solution but I also echo other people's concerns about the approach. You may want to have a global controller that you drop on the body for things that can happen anywhere and in most of the other controllers and just call through that. Eg

<body ng-controller="GlobalCtrl as gc">
    <h1 ng-click="gc.pingPress()"></h1>
</body>

Anyway here is what I came up with.

<div ng-if="pings">
    <h1 ng-click="pings.press()">asdf</h1>
</div>
<div ng-if="!pings">
    <div ng-controller="PingsCtrl as pings">
        <h1 ng-click="pings.press()">asdf</h1>
    </div>
</div>

This will work if it is dropped inside or outside of an existing PingsCtrl.

Here is a plunker.

https://plnkr.co/edit/4x0kSazcg0g0BsqPKN9C?p=preview

Upvotes: 3

Harris
Harris

Reputation: 1785

Just use a service. It's really the intended structure for having common data and functionality between pages.

Part of the problem with what you were attempting is, whether or not you manage to preserve the controller, Angular has its own management that won't follow you with that, and will be refreshing components without you. You'll run into things like a $scope that doesn't actually match the page you're looking at, and it ends up causing more problems than it's worth.

Upvotes: 7

Related Questions