了解Angular.js控制器参数


80

我刚刚开始学习Angular.js,并且一直在Angular主页上的“连接后端”示例中查看project.js

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

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:'/'});
});

我能找到到目前为止,这可能解释发生了什么事情的唯一的事情是“注入服务整合到控制器”,这说明$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. 在哪里可以看到Angular.js提供的所有服务,例如$location$timeout?(我试图找到列表,但失败了。)


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

1
4.就像您似乎了解的那样,控制器的参数是从控制器的定义中按角度注入的。Angular将查找所有已注册的服务,并尝试查找与指定参数名称匹配的项并注入相应的服务!
jpmorin

3.在定义项目模块时,还包括了Firebase模块的依赖关系。在Firebase模块内部,必须有一个类似于以前的fbURL的angularFire服务。
jpmorin

1
2.这是定义控制器的正确方法:angular.module('project').controller('EditCtrl', ['$scope', '$location', '$routeParams', 'angularFire', 'fbURL', function($scope, $location, $routeParams, angularFire, fbURL) { ... } ]);这样,您首先设置要注入的服务的名称,然后根据需要为这些服务指定其他名称。实际上,如果以后要最小化角度代码,则这是强制性的(因为最小化将重命名变量,所以角度仍然需要能够找到服务名称)。
jpmorin

1
@jpmorin只是添加您的评论作为答案,它们都是正确的。
toxaq

Answers:


152
  • 控制器参数可以是什么?

    该控制器的参数是依赖关系,其被注入由AngularJS喷射器的服务。他们可以是任何东西。但是它们通常是将在控制器内部使用的服务

  • 带有参数的控制器功能在哪里调用?

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

    您所说的与之相关的事物具有一个名称:dependency,如上所述。您所说的魔术是实际使用的AngularJS依赖项注入机制。

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

    很简单。您可以通过多种方法来指导您对注射器的“依赖性”(由注射器管理的参数)。

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

    您将在AngularJS世界中看到很多数组符号用法。现在您开始了解它。你甚至可以注入$scope,并angularFire与使用它们的其他名字在你的函数(更改名称是不建议-在这里这个例子是为了学习目的):['$scope', 'angularFire', function(skop, af) {}]-这样一来,在函数内部可以使用$范围为“skop”和angularFire为“ af”。该顺序数组中的服务相匹配的参数的顺序。

另一个例子:

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方法...几乎所有方法都作为参数接收:name和一些“ stuff ”(其中“ stuff”几乎总是一个函数,定义了控制器,工厂或指令) )。正是所有这些“东西”都将通过其指定的名称注入

    默认情况下,AngularJS服务(如“ $ timeout”,“ $ http”等)可用,因为ng模块已由框架加载。

    对于其他服务,您需要加载/要求模块。这就是你做什么ngRouter火力等..通过加载的模块,其注册的东东都可以注射你的模块/应用程序。

让我们看一个分步示例:

// 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
    }]
);

这就是Firebase之类的东西(例如angularFire)变得可用的方式!我们做了什么?首先,我们创建了“ myModule”,并向其中注册了NAMED内容。后来,我们需要为“ koolModule”使用“ myModule”-并且这些名称已经在注射器name => stuff列表中可用。

  • 如何在参数中链接fbURL

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

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

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

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

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

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


4
谢谢!很好的解释了什么以及为什么。
Kevin Shea 2014年

4
单纯基于命名参数的隐式行为是不直观的,并且绝对令人讨厌,但是感谢您的出色回答。
jarmod

1
@jarmod正是我的想法-在没有先看这篇文章的情况下浏览“ phonecat” AngularJS教程真是令人困惑!
2013年

1
“很简单。” 不。
J. Dimeo '16

2
很棒的解释。在一些教程中,有很多事情是理所当然的。“只要像这样键入它就可以了。” 我需要知道如何以及为什么,这回答了很多问题。非常感谢您的宝贵时间!
约翰·卡雷尔

1

首先,选择此框架非常出色。这是最好的。您看到的带有$符号的变量将被注入并成为标准框架的一部分。这些服务将使您的生活更加轻松。想到控制器的最好方法是脚本表。他们帮助分离代码。不要将它们视为方法。您看到的那些变量(例如$ timeout和$ scope)将在您需要完成某些工作时派上用场。该框架的所有文档都位于http://docs.angularjs.org/api/,但我将从本教程http://docs.angularjs.org/tutorial/开始 。

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

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

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

Angularjs不是您可以通过查看框架提供的东西来学习的框架类型。仅仅是因为它提供了全部。您可能会带来的一切,以使其成为一个出色的应用程序。相反,您应该专注于问Google如何用angular解决问题。

还可以在YouTube上观看视频。您会发现一些很棒的。


1

根据toxaq的评论,这是评论的答案

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

    它可能主要是您在或在路由定义上使用resolve之前定义的服务,工厂,值,常量等。

  2. 带有参数的控制器功能在哪里调用?

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

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

    这样,您首先要设置要注入的服务的名称,然后根据需要为这些服务指定其他名称。实际上,如果以后要最小化角度代码,则这是强制性的(因为最小化将重命名变量,所以角度仍然需要能够找到服务名称)。

  3. 在哪里定义angularFire?

    在定义项目模块时,还包括了Firebase模块的依赖关系。在Firebase模块内部,必须有一个类似于以前的fbURL的angularFire服务。

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

    就像您似乎了解的那样,控制器的参数是从控制器的定义中按角度注入的。Angular将查找所有已注册的服务,并尝试查找与指定参数名称匹配的项,然后注入相应的服务!

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

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


1

带有参数的控制器功能在哪里调用?

控制器功能可使用ngController指令实例化,或者在使用路由创建过程中已提及控制器$routeProvider。AngularJS为您完成了这一工作,并使用注入了您在控制器上定义的参数DI

DI通过匹配参数名称(有时是顺序)来工作。因此$scope将获得当前范围,$http将获得http服务

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.