我有一个控制器负责与API通信,以更新用户的属性,名称,电子邮件等。每个用户都有一个“id”,当查看配置文件页面时,这个“id”从服务器传递过来。

我想把这个值传递给AngularJS控制器,这样它就知道当前用户的API入口点是什么。我试着在ng-controller中传递这个值。例如:

function UserCtrl(id, $scope, $filter) {

$scope.connection = $resource('api.com/user/' + id)

在HTML中

<body ng-controller="UserCtrl({% id %})">

其中{% id %}打印从服务器发送的id。但是会有错误。

在创建控制器时将值传递给控制器的正确方法是什么?


当前回答

你可以在设置路由时这样做。

 .when('/newitem/:itemType', {
            templateUrl: 'scripts/components/items/newEditItem.html',
            controller: 'NewEditItemController as vm',
            resolve: {
              isEditMode: function () {
                return true;
              }
            },
        })

以后用它作为

(function () {
  'use strict';

  angular
    .module('myApp')
    .controller('NewEditItemController', NewEditItemController);

  NewEditItemController.$inject = ['$http','isEditMode',$routeParams,];

  function NewEditItemController($http, isEditMode, $routeParams) {
    /* jshint validthis:true */

    var vm = this;
    vm.isEditMode = isEditMode;
    vm.itemType = $routeParams.itemType;
  }
})();

所以在这里,当我们设置路由时,我们发送:itemType并稍后从$routeParams中检索它。

其他回答

This is an expansion of @Michael Tiller's excellent answer. His answer works for initializing variables from the view by injecting the $attrs object into the controller. The problem occurs if the same controller is called from $routeProvider when you navigate by routing. Then you get injector error Unknown provider : $attrsProvider because $attrs is only available for injection when the view is compiled. The solution is to pass the variable (foo) through $routeParams when initializing controller from route and by $attrs when initializing controller from view. Here's my solution.

从路线

$routeProvider.
        when('/mypage/:foo', {
            templateUrl: 'templates/mypage.html',
            controller: 'MyPageController',
            caseInsensitiveMatch: true,
            resolve: {
                $attrs: function () {
                    return {};
                }
            }
        });

它处理一个url,如'/mypage/bar'。正如你所看到的,foo是通过url param传递的,我们为$attrs提供了一个空白对象,因此注入器没有错误。

从视图

<div ng-controller="MyPageController" data-foo="bar">

</div>

现在是控制器

var app = angular.module('myapp', []);
app.controller('MyPageController',['$scope', '$attrs', '$routeParams'], function($scope, $attrs, $routeParams) {
   //now you can initialize foo. If $attrs contains foo, it's been initialized from view
   //else find it from $routeParams
   var foo = $attrs.foo? $attrs.foo : $routeParams.foo;
   console.log(foo); //prints 'bar'

});

对于我的特定用例,我真的不喜欢这里的任何解决方案,所以我想我应该发布我所做的,因为我在这里没有看到它。

我只是想在ng-repeat循环中使用一个更像指令的控制器:

<div ng-repeat="objParameter in [{id:'a'},{id:'b'},{id:'c'}]">
  <div ng-controller="DirectiveLikeController as ctrl"></div>
</div>

现在,为了在每个DirectiveLikeController中创建时访问objParameter(或在任何时候获得最新的objParameter),我所需要做的就是注入$scope并调用$scope.$eval('objParameter'):

var app = angular.module('myapp', []);
app.controller('DirectiveLikeController',['$scope'], function($scope) {
   //print 'a' for the 1st instance, 'b' for the 2nd instance, and 'c' for the 3rd.
   console.log($scope.$eval('objParameter').id); 
});

我看到的唯一缺点是它要求父控制器知道参数名为objParameter。

看起来对你来说最好的解决方案实际上是一个指令。这允许你仍然拥有你的控制器,但是为它定义自定义属性。

如果你需要访问包装范围内的变量,使用这个:

angular.module('myModule').directive('user', function ($filter) {
  return {
    link: function (scope, element, attrs) {
      $scope.connection = $resource('api.com/user/' + attrs.userId);
    }
  };
});

<user user-id="{% id %}"></user>

如果你不需要访问包装范围内的变量,可以使用这个:

angular.module('myModule').directive('user', function ($filter) {
  return {
    scope: {
      userId: '@'
    },
    link: function (scope, element, attrs) {
      $scope.connection = $resource('api.com/user/' + scope.userId);
    }
  };
});

<user user-id="{% id %}"></user>

视图不应该指定配置

In Angular, the template should never dictate configuration, which is inherently what people desire when they want to pass arguments to controllers from a template file. This becomes a slippery slope. If config settings are hard-coded in templates (such as by a directive or controller argument attribute), you can no longer re-use that template for anything but that single use. Soon you'll want to re-use that template, but with different config and now in order to do so you'll either be pre-processing the templates to inject variables before it gets passed to angular or using massive directives to spit out giant blocks of HTML so you re-use all of the controller HTML except for the wrapper div and it's arguments. For small projects it's no big deal. For something big (what angular excels at), it gets ugly quick.

替代方案:模块

This type of configuration is what modules were designed to handle. In many angular tutorials people have a single module for their entire application, but really the system is designed and fully supports many small modules each which wrap small pieces of the total application. Ideally, controllers, modules etc would be declared in separate files and stitched together in specific re-usable chunks. When your application is designed this way, you get a lot of re-use in addition to easy controller arguments.

The example below has 2 modules, re-using the same controller, but each with their own config settings. That config settings are passed in via dependency injection using module.value. This adheres to the angular way because we have the following: constructor dependency injection, reusable controller code, reusable controller templates (the controller div could easily be included with ng-include), easily unit-testable system without HTML, and lastly re-usable modules as the vehicle for stitching the pieces together.

这里有一个例子:

<!-- index.html -->
<div id="module1">
    <div ng-controller="MyCtrl">
        <div>{{foo}}</div>
    </div>
</div>
<div id="module2">
    <div ng-controller="MyCtrl">
        <div>{{foo}}</div>
    </div>
</div>
<script>
    // part of this template, or a JS file designed to be used with this template
    angular.element(document).ready(function() {
        angular.bootstrap(document.getElementById("module1"), ["module1"]);
        angular.bootstrap(document.getElementById("module2"), ["module2"]);
    });
</script>

<!-- scripts which will likely in be in their seperate files -->
<script>
    // MyCtrl.js
    var MyCtrl = function($scope, foo) {
    $scope.foo = foo;
    }

    MyCtrl.$inject = ["$scope", "foo"];

    // Module1.js
    var module1 = angular.module('module1', []);
    module1.value("foo", "fooValue1");
    module1.controller("MyCtrl", MyCtrl);

    // Module2.js file
    var module2 = angular.module('module2', []);
    module2.value("foo", "fooValue2");
    module2.controller("MyCtrl", MyCtrl);
</script>

查看它的实际运行情况:jsFiddle。

如果使用angular-ui-router,那么这是正确的解决方案:https://github.com/angular-ui/ui-router/wiki#resolve

基本上,在控制器实例化之前声明一组要“解析”的依赖项。你可以为你的每个“状态”声明依赖关系。然后将这些依赖项传递到控制器的“构造函数”中。