0
\$\begingroup\$

I have to pass a bunch of inputs and outputs between two Angular controllers and I've come up with a way to do it using $broadcast. I'm using an "if" statement to make sure the inputs match the outputs, but there must be an easier way.

app.controller('Ctrl2', ['$scope', '$rootScope', function($scope, $rootScope) {
  var myArray = [$scope.input1, $scope.input2];
  $scope.textChange = function(whichChange) {
    if (whichChange == 1) {
      $rootScope.$broadcast('textChanged', $scope.input1, 1);
    } else if (whichChange == 2) {
      $rootScope.$broadcast('textChanged', $scope.input2, 2);
    } //else if, else if, else if, etc...
  };
}]);

But seems there should be a way I can replace that if statement with a single line, something like:

$rootScope.$broadcast('textChanged', $scope.relevantInput, relevantOutput);

Working Plunkr here

Same question applies to the case statement in controller Ctrl1, but I figure answering the question for one controller would answer it for the other.

Also: while comments on whether this is the best way to do this in Angular are certainly welcome my question is more about avoiding if/switch/eval.

\$\endgroup\$
2
  • \$\begingroup\$ I have rolled back your question. See What should I do when someone answers my question? for more information. \$\endgroup\$ Commented Jan 20, 2016 at 23:27
  • \$\begingroup\$ Nicko made a good comment, but I'm not sure it entirely answers my question. The line of code I removed has no bearing on the answer. \$\endgroup\$ Commented Jan 20, 2016 at 23:30

2 Answers 2

2
\$\begingroup\$

The first change I would suggest when using a lot of ifs is to put things in a map. This is assuming you know what values are expecting from whichChange:

app.controller('Ctrl2', ['$scope', '$rootScope', function($scope, $rootScope) {
  var inputById = { 
    "1": $scope.input1, 
    "2": $scope.input2
  };
  $scope.textChange = function(whichChange) {
    var input = inputById[whichChange.toString()];
    $rootScope.$broadcast('textChanged', input, whichChange);
  };
}]);
\$\endgroup\$
3
  • \$\begingroup\$ Nicko am I wrong in pointing out that inputById will not be in scope inside of $scope.textChange()? \$\endgroup\$ Commented Jan 21, 2016 at 22:38
  • 1
    \$\begingroup\$ Unless I am mistaken - which is possible because I don't know if Angular plays funny games with this inside handlers attached to the scope - the new function object created for your textChange handler is a closure which will contain a reference to its current scope regardless of where it is executed. Here's an example: jsbin.com/dasexokexu/edit?js,console In fact, it may be a faux pas to add closures to $scope, according to this: thinkingmedia.ca/2015/01/… \$\endgroup\$ Commented Jan 21, 2016 at 23:38
  • \$\begingroup\$ Dang, just when I think I have a hold on Angular, something else comes along to push it out of my reach! \$\endgroup\$ Commented Jan 22, 2016 at 18:12
3
\$\begingroup\$

Now The Angular Way™ to do this is to push off the data to a higher scope visible to both controllers and let two-way binding do its thing. This is typically done by using a parent controller. Scope operates similar to prototypal inheritance. If it's not in the child scope, it looks for it in the parent scope.

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

app.controller('ParentController', function($scope) {
  $scope.data = {
    data1: 'data1',
    data2: 'data2',
  }
});

app.controller('Ctrl1', function($scope) {
  // Stuff local to Ctrl 1
});


app.controller('Ctrl2', function($scope) {
  // Stuff local to Ctrl 2
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="plunker">
  <div ng-controller="ParentController">
    <div ng-controller='Ctrl1'>
      Output 1: {{data.data1}}
      <br>Output 2: {{data.data2}}
    </div>
    <div ng-controller='Ctrl2'>
      Input 1:
      <input type='text' ng-model='data.data1'>
      <br>Input 2:
      <input type='text' ng-model='data.data2'>
    </div>
  </div>
</div>

This works for small apps. When your apps become large, it's better if you use a service/factory/provider. Use it to hold your data, expose an API to mutate the data and make it emit events when data changes. That way, controllers can pull them in as dependencies, call the API and listen to data changes.

As for other things, Angular allows you to define controllers with implicit dependency format. It uses the name of the variables introduced to the function as the names of the dependencies.

\$\endgroup\$
1
  • \$\begingroup\$ Not a bad response, and I appreciate it, but the question was more about the mapping of the data and not the approach in Angular. \$\endgroup\$ Commented Jan 21, 2016 at 22:16

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.