您可以在创建时将参数传递给 AngularJS 控制器吗?

IT技术 javascript angularjs
2021-01-19 13:27:43

我有一个控制器负责与 API 通信以更新用户、姓名、电子邮件等的属性。每个用户都有一个'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。但我收到错误。

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

6个回答

笔记:

这个答案是旧的。这只是关于如何实现预期结果的概念证明。但是,根据下面的一些评论,它可能不是最佳解决方案。我没有任何文件支持或拒绝以下方法。请参阅下面的一些评论以进一步讨论该主题。

原答案:

我回答是的,你绝对可以使用ng-init一个简单的 init 函数来做到这一点

这是它在plunker上的例子

HTML

<!DOCTYPE html>
<html ng-app="angularjs-starter">
  <head lang="en">
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
    <script src="app.js"></script>
  </head>  
  <body ng-controller="MainCtrl" ng-init="init('James Bond','007')">
    <h1>I am  {{name}} {{id}}</h1>
  </body>
</html>

JavaScript

var app = angular.module('angularjs-starter', []);

app.controller('MainCtrl', function($scope) {

  $scope.init = function(name, id)
  {
    //This function is sort of private constructor for controller
    $scope.id = id;
    $scope.name = name; 
    //Based on passed argument you can make a call to resource
    //and initialize more objects
    //$resource.getMeBond(007)
  };


});
好吧,我认为文档很差,只推荐反对这种方法而没有给出原因。我认为这是一个绝妙的方法。如果框架作者不希望以他们认为“错误”的方式使用该框架,那么他们不应该使以“错误”的方式使用该框架成为可能……并就“错误”提供指导。正确的方法!
2021-03-15 13:27:43
一个警告——如果你试图绑定到一个范围值,或者真的做任何期望值出现在控制器函数中的事情,它在ng-init发生之前已经运行了控制器函数——请参阅plnkr.co/edit /donCm6FRBSX9oENXh9WJ?p=预览
2021-03-20 13:27:43
感谢这一点 - 为我节省了很多麻烦,它非常适合我的情况。我必须用一个对象 ID 初始化我的控制器,这是正确的。
2021-03-24 13:27:43
从文档The only appropriate use of ngInit for aliasing special properties of ngRepeat, as seen in the demo below. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.
2021-04-06 13:27:43
答案清楚地表明该文档不推荐这种方法,但是有人可以指出文档提供官方解决方案的地方吗?
2021-04-14 13:27:43

我已经很晚了,我不知道这是否是一个好主意,但是您可以$attrs在控制器函数中包含可注入对象,从而允许使用元素上提供的“参数”来初始化控制器,例如

app.controller('modelController', function($scope, $attrs) {
    if (!$attrs.model) throw new Error("No model for modelController");

    // Initialize $scope using the value of the model attribute, e.g.,
    $scope.url = "http://example.com/fetch?model="+$attrs.model;
})

<div ng-controller="modelController" model="foobar">
  <a href="{{url}}">Click here</a>
</div>

同样,不知道这是否是一个好主意,但它似乎有效并且是另一种选择。

这实际上比使用更可靠ng-init——如果你试图绑定到一个范围值,它在ng-init发生之前已经运行了控制器功能——见plnkr.co/edit/donCm6FRBSX9oENXh9WJ?p=preview
2021-03-15 13:27:43
我不会用指令等重新发明轮子。如果你有一个控制器,你想在多个视图中使用几个不同的初始化参数,这是最简单和最可靠的解决方案。
2021-03-25 13:27:43
我将如何使用这种方法传递对象?var obj = {a: 1, b: 2};
2021-04-02 13:27:43
@Neil:你必须对你的 json 对象进行字符串化,然后在控制器中解析它。不是更好的解决方案,但它可能有效。Michael 的解决方案适用于类似字符串的参数......
2021-04-03 13:27:43
这是解决生成混合应用程序问题的非常合理的解决方案。
2021-04-05 13:27:43

这也有效。

Javascript:

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

app.controller('MainCtrl', function($scope, name, id) {
    $scope.id = id;
    $scope.name = name;
    // and more init
});

网址:

<!DOCTYPE html>
<html ng-app="angularApp">
  <head lang="en">
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
    <script src="app.js"></script>
    <script>
       app.value("name", "James").value("id", "007");
    </script>
  </head>
  <body ng-controller="MainCtrl">
    <h1>I am  {{name}} {{id}}</h1>
  </body>
</html>
我更喜欢这个解决方案。我能够通过参数传递module化我的重复代码。干杯!
2021-03-20 13:27:43
这是否实质上设置了全局键/值对?是否可以将这些范围限定为给定的控制器实例,以便仅在主控制器下的子控制器上使用它?如果不是,这似乎与仅在窗口级别设置常规全局 Javascript 变量没有太大不同。
2021-03-30 13:27:43
这是一个很好的解决方案,适用于现有的构造函数注入机制。本质上,您正在创建两个名为“name”和“id”的简单服务。注入器负责在构造过程中按名称匹配它们。请参阅:docs.angularjs.org/guide/providers的 Value Recipe 部分
2021-04-05 13:27:43
这看起来是最惯用的方式,但我不确定它是否被 angular 团队推荐
2021-04-05 13:27:43
好的。请注意,这也适用于对象,而不仅仅是像字符串这样的原始类型。
2021-04-06 13:27:43

视图不应规定配置

在 Angular 中,模板永远不应该规定配置,这是人们想要从模板文件向控制器传递参数时所希望的。这变成了一个滑坡。如果配置设置在模板中是硬编码的(例如通过指令或控制器参数属性),则除了一次性使用之外,您不能再将该模板重新用于任何其他用途。很快你会想要重用那个模板,但是使用不同的配置,现在为了这样做,你要么在传递给 angular 之前预处理模板以注入变量,要么使用大量指令来吐出巨型HTML 块,因此您可以重新使用除包装器 div 及其参数之外的所有控制器 HTML。对于小项目来说,这没什么大不了的。对于大的东西(angular 擅长什么),它很快就会变得丑陋。

替代方案:module

这种类型的配置是module设计用来处理的。在许多 angular 教程中,人们为他们的整个应用程序使用一个module,但实际上系统是经过设计的并且完全支持许多小module,每个小module都包含整个应用程序的一小部分。理想情况下,控制器、module等将在单独的文件中声明,并在特定的可重用块中拼接在一起。当您的应用程序以这种方式设计时,除了简单的控制器参数之外,您还可以得到很多重用。

下面的示例有 2 个module,重复使用相同的控制器,但每个module都有自己的配置设置。该配置设置通过依赖注入使用module.value. 这遵循 angular 方式,因为我们有以下内容:构造函数依赖注入、可重用的控制器代码、可重用的控制器模板(控制器 div 可以很容易地包含在 ng-include 中)、无需 HTML 即可轻松进行单元测试的系统,以及最后可重用的module作为将部件缝合在一起的工具。

下面是一个例子:

<!-- 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

我已经投了赞成票,但我想对您的贡献表示感谢。这个答案让我走上了更好的道路。当人们分享最佳实践而不仅仅是 hacky 片段时,stackoverflow 是最好的。这太棒了:“模板永远不应该规定配置,当人们想要将参数从模板文件传递给控制器​​时,这本质上是人们所希望的”。感谢您将激光视觉洞察到问题的核心。
2021-04-08 13:27:43

像@akonsu和Nigel Findlater建议,可以读取URL其中URL是index.html#/user/:id$routeParams.id和使用它的控制器内。

你的应用:

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

app.config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/:type/:id', {templateUrl: 'myView.html', controller: 'myCtrl'});
}]);

资源服务

app.factory('MyElements', ['$resource', function($resource) {
     return $resource('url/to/json/:type/:id', { type:'@type', id:'@id' });
}]);

控制器

app.controller('MyCtrl', ['$scope', '$routeParams', 'MyElements', function($scope, $routeParams, MyElements) {
    MyElements.get({'type': $routeParams.type, "id": $routeParams.id }, function(elm) {
        $scope.elm = elm;
    })
}]);

然后,elm可在视图中访问,具体取决于id.