SoFunction
Updated on 2025-04-08

angular JS understanding the controller component

In angular, controller is a javascript function (type/class) that is used to extend an angular scope other than root scope (https:///article/) instance. When we or angular create a new child scope through the scope.$new API (/api/ng.$#$new), there is an option to pass it into the controller as a parameter of the method (I didn't understand it here, I only know that the first parameter of the controller is a newly created scope, with a parent scope bound to it). This will tell angular that the controller and the new scope need to be combined, and extend its behavior.

Controller can be used as:

1. Set the initial state of the scope object.
2. Add behavior to scope.

1. Setting up the initial state of a scope object

Usually, when we create an application, we need to set the initialization state for the angular scope.

angular applies a new scope object to the controller constructor (it is estimated to be passed in as a parameter), and establishes the initial scope state. This means that angular never creates controller type instances (i.e., does not use the new operator for controller's constructor). The constructor is always applied to existing scope objects.

We create the initial state of scope by creating the model attribute. For example:

                function GreetingCtrl ($scope) {$ = “Hola!”;}

The controller "GreetingCtrl" creates a model called "greeting" that can be applied to the template.

2. Adding Behavior to a Scope Object

The behavior on an angular scope object is in the form of scope method attributes for templates and views. This behavior can modify the application's model.

As guided by the model chapter (https:///article/As discussed, any object (or primitive type) is assigned to the scope and becomes a model property. Any function attached to the scope is available for template views, and can be called via angular expression or via ng event handler directive (such as ngClick).

3. Using Controllers Correctly

Generally speaking, controllers should not try to do too much. It should only contain the business logic required for a single view (and it has not turned around and I have always thought that Controller is just a forwarding...).

To keep the controller simple, the common way is to extract the work that does not belong to the controller into the service, and use these services through dependency injection in the controller. These things will be discussed in the Dependency Injection Services chapter of the wizard.

Don't do the following in the Controller:

  1. Any type of DOM operation - controller should only contain business logic. DOM operation, that is, the application's performance logic, is well known for its testing difficulty. Putting any representation logic into the controller greatly affects the testability of the application logic. angular provides data binding (to automatically operate (update) the DOM (/guide/dev_guide.). If we want to perform our custom DOM operations, we can extract the presentation logic to directive(https:///article/)middle.
  2. Input formatting - use angular form controls (https:///article/)replace.
  3. Output filtering - Use angular filters instead.
  4. Execute stateless or stateful, controller-shared code - use angular services instead.
  5. Instantiate or manage the life cycle of other components (for example, create a service instance).

4. Associating Controllers with Angular Scope Objects

We can explicitly associate controller and scope objects through scope.$new, or implicitly use ngController directive (/api/:ngController) or $route service (/api/ng.$route).

1. Example of Controller constructor and method

To illustrate how the controller component works in angular, let's create a small application using the following components:

  1. A template with two buttons and a simple message.
  2. A model composed of a string attribute called "spice".
  3. A controller with two methods that set spice properties.

The message in our template contains a binding to the spice model, which is set to "very" by default. Set the value of spice model to "chili" or "jalapeño" according to the button being clicked, and the message will be automatically updated by data binding.

<!DOCTYPE html>
<html ng-app>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <title>spicy-controller</title>
 <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
 <style type="text/css">
 .ng-cloak {
  display: none;
 }
 </style>
</head>
<body class="ng-cloak">
 <div ng-controller="SpicyCtrl">
 <button ng-click="chiliSpicy()">Chili</button>
 <button ng-click="jalapenoSpicy('jalapeño')">Jalapeño</button>
 <p>The food is {{spice}} spicy!</p>
 </div>

 <script src="../angular-1.0." type="text/javascript"></script>
 <script type="text/javascript">
 function SpicyCtrl($scope) {
  $ = "very";
  $ = function() {
  $ = "chili";
  };
  $ = function(val) {
   = val;
  };
 }
 </script>
</body>
</html>

Things to note in the above example:

  1. ngController directive is used as our template (implicitly) to create scope, which will be called SpicyCtrl parameter.
  2. SpicyCtrl is just a normal javascript function. As a (random) naming rule, the name begins with capital letters and ends with "Ctrl" or "Controller".
  3. Assigning attribute values ​​can create or update $scope's model.
  4. The controller method can be created by directly assigning to $scope. (chiliSpicy method)
  5. Both methods of controller are available in templates (effective in both the element where the ng-controller attribute resides as well as its child elements).
  6. Note: Previous versions of angular (before 1.0RC) allow us to use this instead of $scope to define $scope, but it does not apply here anymore. In methods defined on scope, this is equivalent to $scope (angular takes this to scope), but not in our controller constructor.
  7. Note: The previous version of angular (before 1.0RC) would automatically add the controller's prototype method to the scope, but now it won't. All methods need to be added manually to the scope. (I remember there was a guide before, and I used this. It has not been updated yet -_-!)

The controller method can take parameters, as shown in the following example:

<!DOCTYPE html>
<html ng-app>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <title>controller-method-aruments</title>
 <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
 <style type="text/css">
 .ng-cloak {
  display: none;
 }
 </style>
</head>
<body class="ng-cloak">
 <div ng-controller="SpicyCtrl">
 <input ng-model="customSpice" value="wasabi"/>
 <button ng-click="spicy(customSpice)">customSpice</button>
 <br/>
 <button ng-click="spicy('Chili')">Chili</button>
 <p>The food is {{spice}} spicy!</p>
 </div>

 <script src="../angular-1.0." type="text/javascript"></script>
 <script type="text/javascript">
 function SpicyCtrl($scope) {
  $ = "very";
  $ = function(spice) {
  $ = spice;
  };
 }
 </script>
</body>
</html>

Note that the SpicyCtrl controller now only defines a method with a parameter "spice" and called "spicy". template can refer to the controller method and pass a constant string or model value to it.

Controller inheritance in angular is based on scope inheritance. Let's take a look at the following example:

&lt;!DOCTYPE html&gt;
&lt;html ng-app&gt;
&lt;head&gt;
 &lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8"/&gt;
 &lt;title&gt;controller-inheritance&lt;/title&gt;
 &lt;meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible"&gt;
 &lt;style type="text/css"&gt;
 .ng-cloak {
  display: none;
 }
 &lt;/style&gt;
&lt;/head&gt;
&lt;body class="ng-cloak"&gt;
 &lt;div ng-controller="MainCtrl"&gt;
 &lt;p&gt;Good {{timeOfDay}}, {{name}}!&lt;/p&gt;
 &lt;div ng-controller="ChildCtrl"&gt;
  &lt;p&gt;Good {{timeOfDay}}, {{name}}!&lt;/p&gt;
  &lt;p ng-controller="BabyCtrl"&gt;Good {{timeOfDay}}, {{name}}!&lt;/p&gt;
 &lt;/div&gt;
 &lt;/div&gt;

 &lt;script src="../angular-1.0." type="text/javascript"&gt;&lt;/script&gt;
 &lt;script type="text/javascript"&gt;
 function MainCtrl($scope) {
  $ = 'Main time';
  $ = 'Main name';
 }

 function ChildCtrl($scope) {
  $ = 'Child name';
 }

 function BabyCtrl($scope) {
  $ = 'Baby time';
  $ = 'Baby name';
 }
 &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;

Notice how we nest 3 ngController directly into the template. For our view, this template structure will cause 4 scopes to be created:

  1. root scope。
  2. MainCtrl scope, including timeOfDay and name model.
  3. ChildCtrl scope, overrides the name model of MainCtrl scope, inherits the timeOfDay model.
  4. BabyCtrl scope, overrides the timeOfDay of MainCtrl scope and the name of ChildCtrl scope.

The inherited work is the same in controller and model. So in our previous example, all models can be rewritten through the controller.

Note: Standard prototype inheritance between two controllers does not work as we thought, because as we mentioned earlier, the controller is not initialized directly through angular, but instead applies that scope object. (controllers are not instantiated directly by angular, but rather are applied to the scope object, here is the same as before, I still don't understand.)

5. Testing Controller

While there are many ways to test controllers, one of the best conventions, as shown below, requires injection of $rootScope and $controller. (The test requires cooperation)

<!DOCTYPE html>
<html ng-app>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <title>controller-test</title>
 <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
 <link rel="stylesheet" href="../">
 <style type="text/css">
 .ng-cloak {
  display: none;
 }
 </style>
</head>
<body class="ng-cloak">

<script src="../angular-1.0." type="text/javascript"></script>
<script src="../angular-scenario-1.0." type="text/javascript"></script>
<script src="../" type="text/javascript"></script>
<script src="../" type="text/javascript"></script>
<script src="../angular-mocks-1.0." type="text/javascript"></script>
<script type="text/javascript">
 function MyController($scope) {
 $ = [
  {"name":"pasilla", "spiciness":"mild"},
  {"name":"jalapeno", "spiceiness":"hot hot hot!"},
  {"name":"habanero", "spiceness":"LAVA HOT!!"}
 ];

 $ = "habanero";
 }
 describe("MyController function", function () {
 describe("MyController", function () {
  var scope;
  beforeEach(inject(function ($rootScope, $controller) {
  scope = $rootScope.$new();
  var ctrl = $controller(MyController, {$scope:scope});
  }));

  it('should create "cpices" model with 3 spices', function () {
  expect().toBe(3);
  });

  it('should set the default value of spice', function () {
  expect().toBe("habanero");
  });
 });
 });

 (function () {
 var jasmineEnv = ();
  = 1000;

 var trivialReporter = new ();

 (trivialReporter);

  = function (spec) {
  return (spec);
 };

 var currentWindowOnload = ;

  = function () {
  if (currentWindowOnload) {
  currentWindowOnload();
  }
  execJasmine();
 };

 function execJasmine() {
  ();
 }

 })();

</script>
</body>
</html>

 

If we need to test the nested controller, we need to create the same scope inheritance relationship in the test as in the DOM.

&lt;!DOCTYPE html&gt;
&lt;html ng-app&gt;
&lt;head&gt;
 &lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8"/&gt;
 &lt;title&gt;controller-test&lt;/title&gt;
 &lt;meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible"&gt;
 &lt;link rel="stylesheet" href="../"&gt;
 &lt;style type="text/css"&gt;
 .ng-cloak {
  display: none;
 }
 &lt;/style&gt;
&lt;/head&gt;
&lt;body class="ng-cloak"&gt;

&lt;script src="../angular-1.0." type="text/javascript"&gt;&lt;/script&gt;
&lt;script src="../angular-scenario-1.0." type="text/javascript"&gt;&lt;/script&gt;
&lt;script src="../" type="text/javascript"&gt;&lt;/script&gt;
&lt;script src="../" type="text/javascript"&gt;&lt;/script&gt;
&lt;script src="../angular-mocks-1.0." type="text/javascript"&gt;&lt;/script&gt;
&lt;script type="text/javascript"&gt;
 function MainCtrl($scope) {
 $ = 'Main time';
 $ = 'Main name';
 }

 function ChildCtrl($scope) {
 $ = 'Child name';
 }

 function BabyCtrl($scope) {
 $ = 'Baby time';
 $ = 'Baby name';
 }

 describe("MyController", function () {
 var mainScope,childScope,babyScope;
 beforeEach(inject(function ($rootScope, $controller) {
  mainScope = $rootScope.$new();
  var mainCtrl = $controller(MainCtrl, {$scope:mainScope});
  childScope = mainScope.$new();
  var childCtrl = $controller(ChildCtrl, {$scope:childScope});
  babyScope = childScope.$new();
  var babyCtrl = $controller(BabyCtrl, {$scope:babyScope});
 }));

 it('should have over and selected', function () {
  expect().toBe("Main Time");
  expect().toBe("Main Name");
  expect().toBe("Main Time");
  expect().toBe("Child Name");
  expect().toBe("Baby Time");
  expect().toBe("Baby Name");
 });
 });

 (function () {
 var jasmineEnv = ();
  = 1000;

 var trivialReporter = new ();

 (trivialReporter);

  = function (spec) {
  return (spec);
 };

 var currentWindowOnload = ;

  = function () {
  if (currentWindowOnload) {
  currentWindowOnload();
  }
  execJasmine();
 };

 function execJasmine() {
  ();
 }

 })();

&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;

The above is the information about AngularJs Understanding the Controller Component. We will continue to add relevant information in the future. Thank you for your support!