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

nic*_*ine 278 javascript angularjs

我有一个控制器负责与API通信以更新用户的属性,名称,电子邮件等.每个用户都有一个'id'在查看个人资料页面时从服务器传递的用户.

我想将此值传递给AngularJS控制器,以便它知道当前用户的API入口点是什么.我试过传递价值ng-controller.例如:

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

$scope.connection = $resource('api.com/user/' + id)
Run Code Online (Sandbox Code Playgroud)

并在HTML中

<body ng-controller="UserCtrl({% id %})">
Run Code Online (Sandbox Code Playgroud)

其中{% id %}打印从服务器发送的id.但我得到错误.

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

小智 359

笔记:

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

原答案:

我回答这个是你绝对可以使用ng-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>
Run Code Online (Sandbox Code Playgroud)

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


});
Run Code Online (Sandbox Code Playgroud)

  • 好吧,我认为在没有说明理由的情况下,仅仅建议反对这种方法的文档很差.我认为这是一个很好的方法.如果框架作者不希望框架以"错误"的方式用于它们,那么它们就不应该以"错误"的方式使用...并提供关于"正确的方法! (53认同)
  • [来自docs](http://docs.angularjs.org/api/ng.directive:ngInit):`ngInit唯一合适的用于别名ngRepeat的特殊属性,如下面的演示所示.除了这种情况,您应该使用控制器而不是ngInit来初始化范围上的值 (26认同)
  • 答案清楚地说明了文档建议不采用这种方法,但有人可以指出文档提供官方解决方案的地方吗? (8认同)
  • 多亏了这一点 - 为我节省了很多头脑,它完全符合我的情况.我不得不用对象ID初始化我的控制器,这是正确的. (4认同)
  • 一句警告 - 如果你试图绑定到一个范围值,或者真的做任何期望值存在于控制器函数中的东西,它已经在`ng-init`发生之前运行了控制器函数 - 请参阅http://plnkr.co/edit/donCm6FRBSX9oENXh9WJ?p=preview (2认同)

Mic*_*ler 141

我已经很晚了,我不知道这是不是一个好主意,但你可以$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>
Run Code Online (Sandbox Code Playgroud)

再一次,不知道这是不是一个好主意,但似乎有效,是另一种选择.

  • 我如何使用这种方法传递对象?var obj = {a:1,b:2}; (3认同)
  • 这是生成混合应用程序问题的一个非常合理的解决方案. (3认同)
  • @Neil:你必须对你的json对象进行字符串化,然后在控制器内解析它.不是更好的解决方案,但它可能有效.迈克尔的解决方案适用于类似字符串的参数...... (2认同)
  • 我没有通过指令等重新发明轮子.如果你想在多个视图中使用一个控制器,只有几个不同的初始化参数,这是*最简单*和最可靠的解决方案. (2认同)

Jon*_*ark 39

这也有效.

使用Javascript:

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

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

HTML:

<!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>
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的解决方案,适用于现有的构造函数注入机制.实际上,您创建了两个名为"name"和"id"的简单服务.注射器在施工期间按名称进行匹配.请参阅:https://docs.angularjs.org/guide/providers的Value Recipe部分 (3认同)

Fra*_*ain 15

像@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'});
}]);
Run Code Online (Sandbox Code Playgroud)

资源服务

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

控制器

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

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


Nuc*_*eon 14

视图不应该指定配置

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

替代方案:模块

这种配置是模块设计用来处理的.在许多角度教程中,人们对整个应用程序都有一个模块,但实际上系统是设计完全支持许多小模块,每个模块都包含整个应用程序的一小部分.理想情况下,控制器,模块等将在单独的文件中声明,并在特定的可重用块中拼接在一起.当您的应用程序以这种方式设计时,除了简单的控制器参数之外,您还可以重复使用.

下面的示例有2个模块,重新使用相同的控制器,但每个模块都有自己的配置设置.该配置设置通过依赖注入使用传入module.value.这符合角度方式,因为我们有以下内容:构造函数依赖注入,可重用控制器代码,可重用控制器模板(控制器div可以很容易地包含在ng-include中),易于单元测试的系统,没有HTML,最后可重复使用模块作为拼接在一起的车辆.

这是一个例子:

<!-- 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>
Run Code Online (Sandbox Code Playgroud)

看到它的实际效果:jsFiddle.


Ser*_*ney 8

如果ng-init不是为了传递对象$scope,你总是可以编写自己的指令.所以这就是我得到的:

http://jsfiddle.net/goliney/89bLj/

Javasript:

var app = angular.module('myApp', []);
app.directive('initData', function($parse) {
    return function(scope, element, attrs) {
        //modify scope
        var model = $parse(attrs.initData);
        model(scope);
    };
});

function Ctrl1($scope) {
    //should be defined
    $scope.inputdata = {foo:"east", bar:"west"};
}
Run Code Online (Sandbox Code Playgroud)

HTML:

<div ng-controller="Ctrl1">
    <div init-data="inputdata.foo=123; inputdata.bar=321"></div>
</div>
Run Code Online (Sandbox Code Playgroud)

但我的方法只能修改已在控制器中定义的对象.


bte*_*ser 8

看起来最适合您的解决方案实际上是一个指令.这允许您仍然拥有控制器,但为其定义自定义属性.

如果需要访问包装范围中的变量,请使用此选项:

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>
Run Code Online (Sandbox Code Playgroud)

如果您不需要访问包装范围中的变量,请使用此选项:

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>
Run Code Online (Sandbox Code Playgroud)


Dmi*_*zin 7

我发现来自$ routeProvider的传递变量很有用.

例如,您将一个控制器MyController用于多个屏幕,并在其中传递一些非常重要的变量"mySuperConstant".

使用这个简单的结构:

Router:

$routeProvider
            .when('/this-page', {
                templateUrl: 'common.html',
                controller: MyController,
                mySuperConstant: "123"
            })
            .when('/that-page', {
                templateUrl: 'common.html',
                controller: MyController,
                mySuperConstant: "456"
            })
            .when('/another-page', {
                templateUrl: 'common.html',
                controller: MyController,
                mySuperConstant: "789"
            })

MyController:

    MyController: function ($scope, $route) {
        var mySuperConstant: $route.current.mySuperConstant;
        alert(mySuperConstant);

    }
Run Code Online (Sandbox Code Playgroud)


ssa*_*ini 6

您可以在设置例如路线时执行此操作

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

后来用它作为

(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;
  }
})();
Run Code Online (Sandbox Code Playgroud)

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