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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14523679/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 17:05:00  来源:igfitidea点击:

Can you pass parameters to an AngularJS controller on creation?

javascriptangularjs

提问by nickponline

I have a controller responsible for communicating with an API to update properties of a user, name, email, etc. Each user has an 'id'which is passed from the server when the profile page is viewed.

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

I would like to pass this value to the AngularJS controller so it knows what the API entry point is for the current user. I've tried passing the value in ng-controller. For example:

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

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

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

and in the HTML

并在 HTML 中

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

where {% id %}print the id sent from the server. but I get errors.

在哪里{% id %}打印从服务器发送的 id。但我收到错误。

What is the correct way to pass a value into a controller on its creation?

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

回答by Jigar Patel

Notes:

笔记:

This answer is old. This is just a proof of concept on how the desired outcome can be achieved. However, it may not be the best solution as per some comments below. I don't have any documentation to support or reject the following approach. Please refer to some of the comments below for further discussion on this topic.

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

Original Answer:

原答案:

I answered this to Yes you absolutely can do so using ng-initand a simple init function.

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

Here is the example of it on plunker

这是它在plunker上的例子

HTML

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

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


});

回答by Michael Tiller

I'm very late to this and I have no idea if this is a good idea, but you can include the $attrsinjectable in the controller function allowing the controller to be initialized using "arguments" provided on an element, e.g.

我已经很晚了,我不知道这是否是一个好主意,但是您可以$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>

Again, no idea if this is a good idea, but it seems to work and is another alternative.

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

回答by Jonghee Park

This also works.

这也有效。

Javascript:

Javascript:

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

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

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>

回答by Nucleon

The view should not dictate config

视图不应规定配置

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.

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

The Alternative: Modules

替代方案:模块

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.

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

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.

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

Here's an example:

下面是一个例子:

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

See it in action: jsFiddle.

在行动中看到它:jsFiddle

回答by Fran?ois Romain

Like @akonsu and Nigel Findlater suggest, you can read the url where url is index.html#/user/:idwith $routeParams.idand use it inside the controller.

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

your app:

你的应用:

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

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

the resource service

资源服务

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

the controller

控制器

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

then, elmis accessible in the view depending on the id.

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

回答by Sergey Goliney

If ng-initis not for passing objects into $scope, you can always write your own directive. So here is what I got:

如果ng-init不是为了将对象传递给$scope,您始终可以编写自己的指令。所以这就是我得到的:

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

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

Javasript:

Java脚本:

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

Html:

网址:

<div ng-controller="Ctrl1">
    <div init-data="inputdata.foo=123; inputdata.bar=321"></div>
</div>

But my approach can only modify objects, which are already defined at controller.

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

回答by btesser

It looks like the best solution for you is actually a directive. This allows you to still have your controller, but define custom properties for it.

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

Use this if you need access to variables in the wrapping scope:

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

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>

Use this if you don't need access to variables in the wrapping scope:

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

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>

回答by Dmitri Algazin

I found passing variables from $routeProvider usefull.

我发现从 $routeProvider 传递变量很有用。

For example, you use one controller MyController for multiple screens, passing some very important variable "mySuperConstant" inside.

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

Use that simple structure:

使用这个简单的结构:

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

    }

回答by ssaini

You can do it when setting up the routes for e.g.

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

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

And later use it as

然后将其用作

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

So here when we set up the route we sent :itemType and retrive it later from $routeParams.

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

回答by Nigel Findlater

There is another way to pass parameters to a controller by injecting $routeParams into your controller and then using url parameters described here What's the most concise way to read query parameters in AngularJS?

通过将 $routeParams 注入控制器,然后使用此处描述的 url 参数,还有另一种将参数传递给控制器​​的方法。在 AngularJS 中读取查询参数的最简洁方法是什么?