【问题标题】:Understanding Angular.js controller parameters了解 Angular.js 控制器参数
【发布时间】:2013-10-14 19:33:02
【问题描述】:

我刚开始学习 Angular.js,一直在看project.js in the "Wire up a Backend" example on the Angular home page

我对控制器函数中的参数感到困惑:

function ListCtrl($scope, Projects) {
  ... 
}   

function CreateCtrl($scope, $location, $timeout, Projects) {
  ... 
}

function EditCtrl($scope, $location, $routeParams, angularFire, fbURL) {
   angularFire(fbURL + $routeParams.projectId, $scope, 'remote', {}).
   then(function() {
     ...
   });
}  

这些控制器函数在routeProvider中被调用,但是没有给出任何参数。

$routeProvider.
  when('/', {controller:ListCtrl, templateUrl:'list.html'}).
  when('/edit/:projectId', {controller:EditCtrl, templateUrl:'detail.html'}).
  when('/new', {controller:CreateCtrl, templateUrl:'detail.html'}).
  otherwise({redirectTo:'/'});
});

到目前为止,我能找到的唯一可能解释发生了什么的事情是"Injecting Services Into Controllers",它解释了$location$timeout,但不是参数方法angularFirefbURL

我的具体问题是:

  1. 控制器参数可以是什么?

  2. 在哪里调用带有参数的控制器函数?或者参数没有被调用,而只是与控制器相关联的东西,其中关联发生了很多 Angular.js 魔术(如果是这样,我可以在 github 上查看源代码)吗?

  3. angularFire 在哪里定义?

  4. 参数中的fbURL如何链接到:

    angular.module('project', ['firebase']).
        value('fbURL', 'https://angularjs-projects.firebaseio.com/').
        factory ...
    
  5. 有没有可以看到所有服务的地方,例如$location$timeout,Angular.js 提供的? (我试图找到列表但失败了。)

【问题讨论】:

  • 5.有关 Angular 中包含的所有内置服务、过滤器、指令的列表,请查看 API:docs.angularjs.org/api
  • 4.就像您似乎理解的那样,控制器的参数是从控制器的定义中通过角度注入的。 Angular 会查看所有注册的服务,并尝试找到与指定参数名称匹配的参数并注入相应的服务!
  • 3.定义项目模块时,还包括了 firebase 模块依赖项。在 firebase 模块内部,必须有一个像之前的 fbURL 一样的 angularFire 服务。
  • 2.这是定义控制器的正确方法:angular.module('project').controller('EditCtrl', ['$scope', '$location', '$routeParams', 'angularFire', 'fbURL', function($scope, $location, $routeParams, angularFire, fbURL) { ... } ]); 这样,您首先设置要注入的服务的名称,然后根据需要为这些服务指定不同的名称。事实上,如果你想稍后最小化你的 Angular 代码,这是强制性的(因为最小化会重命名变量,所以 Angular 仍然需要能够找到服务名称)。
  • @jpmorin 只需添加您的 cmets 作为答案,它们都是正确的。

标签: angularjs


【解决方案1】:
  • 控制器参数可以是什么?

    控制器参数为dependencies,由AngularJS注入器服务注入。它们可以是任何东西。但它们通常是控制器内部使用的服务

  • 使用参数调用的控制器函数在哪里?

    控制器,以及 AngularJS 中的指令、过滤器、服务和许多其他东西都是函数。但是框架管理了很多何时以及如何这些函数被调用。

    你所说的stuff associated有一个名字:dependency,如上所述。你所说的ma​​gic是AngularJS的依赖注入机制。

    当注入器调用这些函数(控制器和其他函数)时,它会读取参数名称(例如:$scope$httpangularFire)并搜索具有该名称的注册服务,即然后在调用函数时作为参数提供。

    这很简单。您有几种方法可以将您的“依赖项”(由注入器管理的参数)告知注入器。

    当您简单地将您的函数声明为function myCtrl($scope) {} 时,注入器将能够从参数名称中找到$scope 服务。但是如果你minify JavaScript 代码,注入器将无法再找到服务,因为参数名称将被修改为更小的字符串,如“a”或“x”。为避免此问题,可以使用 数组表示法 指定要注入的服务名称。在这种情况下,您可以像这样声明您的函数:myCtrl = ['$scope', function($scope) {}]

    您会在 AngularJS 世界中看到很多 数组表示法 的用法。现在你开始理解它了。您甚至可以注入 $scopeangularFire 并在您的函数中将它们与 其他名称 一起使用(更改名称不推荐 - 此示例用于学习目的) :['$scope', 'angularFire', function(skop, af) {}] - 这样,在函数内部,您可以使用 $scope 作为“skop”,使用 angularFire 作为“af”。数组中服务的order与参数的顺序相匹配。

另一个例子:

var myController = ['$scope', '$resource', '$timeout',
    function($scope, $resource, $timeout) {
        // this controller uses $scope, $resource and $timeout
        // the parameters are the dependencies to be injected
        // by AngularJS dependency injection mechanism
    }
];
  • angularFire 是在哪里定义的?

    firebase 模块中。

    正如您现在已经知道的那样,注入器将注入任何东西,只要它在其记录中注册了该“事物”名称并可用。如果存在具有该名称的“服务”,他就能够提供它。

    那么,这个注入器使用的name => stuff 列表是如何构建的?

    模块就是答案。 模块只不过是name => stuff 的列表。它位于一个模块中,您可以在其中注册服务、工厂、过滤器、指令等。

    仔细查看Module methods at the official documentation...几乎所有这些都作为参数接收:name和一些“stuff”(其中“stuff”几乎总是函数,定义控制器、工厂或指令)。正是所有这些“东西”将通过它们指定的名称变得可注射

    AngularJS 服务(如“$timeout”、“$http”等)默认可用,因为框架已经加载了 ng 模块

    对于其他服务,您需要加载/需要 模块。这就是你对 ngRouterfirebase 等所做的事情......通过加载 模块,它的注册内容可用于注入 在您的模块/应用中。

让我们看一个分步示例:

// An empty module:
var module = angular.module('myModule', []);

// Now, adding an "injectable" constant: 
module.constant('niceStuff', { blip: 'blop', blup: 307 });

// We could add a service:
module.service('entityManager', ['$http', function($http){  }]);

// and so on... if I wanted to use "$resource" instead of "$http"
// in the entityManager service above...
// ...I would need to require the ngResource when creating the module above,
// like this: var module = angular.module('myModule', ['ngResource']);
// because "$resource" is not available by default

// NOW, anywhere else, since the code above already ran
// I can use those NAMES as dependencies like this:

// We are creating another module now:
var koolModule = angular.module('km', ['myModule']);
// Note that I am requiring the previous module through its registered name

// Now, anything I've declared in that module
// - just like "ng" (by default) and "firebase" (required) does -
// is available for "injection"!!!

koolModule.controller('koolController',
    ['niceStuff', 'entityManager', function(niceStuff, entityManager) {
        console.log(niceStuff.blip);      // 'blop'
        console.log(niceStuff.blup + 10); // 317
    }]
);

这就是 angularFire 之类的 firebase 东西可用的方式!我们做了什么?首先,我们创建了“myModule”,并向其注册了 NAMED 的东西。后来,我们需要为我们的“koolModule”提供“myModule”——而这些名称已经在注入器name => stuff 列表中可用。

  • 参数中的fbURL是如何链接的

    正如我们刚刚看到的,大多数模块方法只是注册事物 - 为事物赋予名称,以便它们可以注入和/或以后通过这些名称使用。

    module.value('fbURL', 'https://angularjs-projects.firebaseio.com/')被调用时,fbURL(和指定的值)被注册到name => stuff列表中......在这种情况下,名称是“fbURL”,值/ stuff 是 URL 字符串 - 但它可以是任何东西!

  • 有没有可以看到所有服务的地方,例如Angular.js 提供的 $location 和 $timeout?

    是的,API 参考:http://docs.angularjs.org/api/

    注意左侧导航的组织方式...由模块!首先是 ng 模块,有大量的指令、服务、过滤器等。然后是下面的其他模块(ngRoute、ngResource、ngMock 等),每个模块都包含自己的服务,过滤器或指令...

感谢有机会分享这些想法。我喜欢写它们。

【讨论】:

  • 谢谢!很好地解释了什么和为什么。
  • 纯粹基于命名参数的存在的隐式行为超出了直觉并且绝对令人讨厌,但感谢您的出色回答。
  • @jarmod 正是我的想法——在没有先看这篇文章的情况下通过“phonecat”AngularJS 教程令人困惑!
  • “很简单。”不。
  • 很棒的解释。在一些教程中有很多事情是理所当然的。 “只需像这样输入它就可以了。”我需要知道如何以及为什么,这回答了很多问题。非常感谢您的宝贵时间!
【解决方案2】:

首先选择这个框架做得很好。这是最好的。您看到的带有 $ 符号的变量是注入的并且是标准框架的一部分。这些服务将使您的生活更加轻松。考虑控制器的最佳方式是它们是脚本表。它们有助于分离代码。不要将它们视为方法。您看到的那些变量,例如 $timeout 和 $scope 是在您需要完成某些事情时会派上用场的服务。该框架的所有文档都位于http://docs.angularjs.org/api/,但我将从本教程开始http://docs.angularjs.org/tutorial/

angularfire 不是框架的一部分。它是另一种利用该框架创建强大的实时分布式网络的服务。当您加载 angularfirejs 时,它附带服务,然后作为您看到的参数注入。

回答您的第二个问题,您传递的参数可以是任何东西,只要您提供相应的服务即可。请参考this为控制器制作自己的参数: http://docs.angularjs.org/guide/dev_guide.services.creating_services

fbURL 只是一个您可以创建的变量,您在问题中放置的代码只是有关如何制作它的说明。

Angularjs 不是那种你可以通过查看它提供的东西来学习的框架类型。仅仅因为它提供了一切。你可以带来的一切来制作一个伟大的应用程序。相反,您应该专注于询问谷歌如何解决您的角度问题。

还可以查看 youtube 上的视频。你会发现一些很棒的。

【讨论】:

    【解决方案3】:

    根据 toxaq 的评论,这里是 cmets 作为答案

    1. 控制器参数可以是什么?

      它主要可以是服务、工厂、值、常量等......您之前在某处定义或在路由定义上使用解析。

    2. 使用参数调用的控制器函数在哪里?

      这是定义控制器的正确方法:

      angular.module('project').controller('EditCtrl', [
          '$scope', 
          '$location', 
          '$routeParams', 
          'angularFire', 
          'fbURL', 
          function($scope, $location, $routeParams, angularFire, fbURL) { 
              ... 
          } 
      ]); 
      

      这样,您首先设置要注入的服务的名称,然后根据需要为这些服务指定不同的名称。事实上,如果你想稍后最小化你的 Angular 代码,这是强制性的(因为最小化会重命名变量,所以 Angular 仍然需要能够找到服务名称)。

    3. angularFire 是在哪里定义的?

      在定义项目模块时,您还包括了 firebase 模块依赖项。在 firebase 模块内部,必须有一个和之前的 fbURL 一样的 angularFire 服务。

    4. 参数中的fbURL是如何链接的

      就像您似乎理解的那样,控制器的参数是通过控制器定义的角度注入的。 Angular 将查看所有注册的服务,并尝试找到与指定参数名称匹配的参数并注入相应的服务!

    5. 有没有可以看到所有服务的地方,例如Angular.js 提供的 $location 和 $timeout?

      有关 Angular 中包含的所有内置服务、过滤器、指令的列表,请查看 API:http://docs.angularjs.org/api

    【讨论】:

      【解决方案4】:

      使用参数调用的控制器函数在哪里?

      控制器函数使用ngController 指令进行实例化,或者如果您在创建路由时使用$routeProvider 提到了控制器。 AngularJS 透明地为您执行此操作,并使用DI 注入您在控制器上定义的参数。

      DI 通过匹配参数的名称(或某些时间顺序)来工作。所以$scope 会得到当前作用域,$http 会得到 http 服务

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-01-05
        • 2013-04-08
        • 2015-12-06
        • 1970-01-01
        • 1970-01-01
        • 2011-07-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多