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

2020/10/07 15:01 · javascript ·  · 0评论

我有一个控制器,负责与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。但我得到了错误。

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

笔记:

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

原始答案:

我对是的回答是肯定的,您绝对可以使用ng-init和简单的初始化函数来做到这一点

这是在punker上的例子

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


});

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

同样,不知道这是否是一个好主意,但它似乎可行,是另一种选择。

这也有效。

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>

该视图不应指示配置

在Angular中,模板绝不应该规定配置,这是人们想要从模板文件将参数传递给控制器​​时所固有的需求。这将成为滑坡。如果配置设置是硬编码在模板中的(例如通过指令或控制器参数属性),则您只能再使用该模板,而不能再使用该模板。很快,您将想要重新使用该模板,但是现在使用不同的配置,因此您可以对模板进行预处理,以在将变量传递给angular之前注入变量,或者使用大量指令吐出巨人HTML块,因此您可以重复使用所有控制器HTML,但包装div及其参数除外。对于小型项目,这没什么大不了的。对于大的东西(角度擅长的东西),它很快就会变得丑陋。

替代方案:模块

这类配置是设计模块处理的。在许多角度教程中,人们为整个应用程序只有一个模块,但是实际上,系统是经过设计的,并且完全支持许多小模块,每个小模块都包装了整个应用程序的小块。理想情况下,控制器,模块等应在单独的文件中声明,并在特定的可重用块中缝合在一起。以这种方式设计应用程序时,除了简单的控制器参数外,您还将获得大量重用。

下面的示例有2个模块,重复使用相同的控制器,但是每个模块都有自己的配置设置。通过使用依赖项注入来传递配置设置module.value这遵循角度的方法,因为我们具有以下内容:构造函数依赖项注入,可重用的控制器代码,可重用的控制器模板(controller 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>

实际使用它:jsFiddle

像@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

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

HTML:

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

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

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

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

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>

我发现从$ 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);

    }

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

 .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中检索它。

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

这个问题很老,但是我努力了很长时间才能找到一个可以满足我的需求并且不容易找到它的答案。我相信我的以下解决方案要比当前接受的解决方案好得多,这也许是因为自从这个问题最初提出以来,角度就增加了功能。

简短的答案,使用Module.value方法允许您将数据传递到控制器构造函数中。

在这里看到我的朋克

我创建一个模型对象,然后将其与模块的控制器关联,并以名称“ model”进行引用

HTML / JS

  <html>
  <head>
    <script>
      var model = {"id": 1, "name":"foo"};

      $(document).ready(function(){
        var module = angular.module('myApp', []);
        module.value('model', model);
        module.controller('MyController', ['model', MyController]);
        angular.bootstrap(document, ['myApp']);
      });

      function confirmModelEdited() {
        alert("model name: " + model.name + "\nmodel id: " + model.id);
      }
    </script>

  </head>
  <body >
      <div ng-controller="MyController as controller">
        id: {{controller.model.id}} <br>
        name: <input ng-model="controller.model.name"/>{{controller.model.name}}
        <br><button ng-click="controller.incrementId()">increment ID</button>
        <br><button onclick="confirmModelEdited()">confirm model was edited</button>
    </div>
  </body>

</html>

然后,控制器中的构造函数将接受具有相同标识符“模型”的参数,然后可以对其进行访问。

控制者

function MyController (model) {
  this.model = model;
}

MyController.prototype.incrementId = function() {
  this.model.id = this.model.id + 1;
}

笔记:

我正在使用bootstrapping的手动初始化,这使我可以在将模型发送到angular之前对其进行初始化。这可以与现有代码配合使用,因为您可以等待设置相关数据,并且仅在需要时才按需编译应用的角度子集。

在插件中,我添加了一个按钮来警告最初在javascript中定义并传递给angular的模型对象的值,只是为了确认angular确实在引用模型对象,而不是复制它并使用副本。

在这行上:

module.controller('MyController', ['model', MyController]);

我将MyController对象传递给Module.controller函数,而不是声明为内联函数。我认为这可以使我们更加清楚地定义控制器对象,但是Angular文档倾向于内联进行,因此我认为需要澄清。

我正在使用“ controller as”语法,并将值分配给MyController的“ this”属性,而不是使用“ $ scope”变量。我相信使用$ scope也可以正常工作,然后控制器分配将如下所示:

module.controller('MyController', ['$scope', 'model', MyController]);

并且控制器构造函数将具有如下签名:

function MyController ($scope, model) {

如果出于任何原因,也可以将此模型附加为第二个模块的值,然后将其作为从属关系附加到主模块。

我相信他的解决方案比目前接受的解决方案好得多,因为

  1. 传递给控制器​​的模型实际上是一个javascript对象,而不是要评估的字符串。它是对对象的真实引用,对其的更改会影响对此模型对象的其他引用。
  2. Angular表示,接受的答案使用ng-init是一种误用,此解决方案无法解决。

在我所见过的大多数其他示例中,Angular的工作方式似乎都是由控制器定义模型数据,这对我而言从来没有道理,模型与控制器之间没有分离,这似乎并不像我的MVC。该解决方案使您可以真正拥有一个完全独立的模型对象,并将其传递给控制器​​。还要注意的是,如果使用ng-include指令,则可以将所有angular html放在单独的文件中,从而将模型视图和控制器完全分成单独的模块。

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

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

一种方法是拥有一个单独的服务,可以将它们用作公共数据成员的论点的“容器”。

我真的不喜欢这里针对我的特定用例的任何解决方案,所以我认为我会发布我所做的事情,因为我在这里没有看到它。

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

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

现在,为了访问objParameter每个DirectiveLikeController中on创建(或随时获取最新的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

不,不可能。我认为您可以将ng-init用作hack http://docs.angularjs.org/api/ng.directive:ngInit

这是一个解决方案(基于Marcin Wyszynski的建议),该解决方案可以在您希望将值传递到控制器中的情况下工作,但您并没有在html中明确声明控制器(ng-init似乎需要)-例如,您正在使用ng-view渲染模板,并通过routeProvider声明相应路由的每个控制器。

JS

messageboard.directive('currentuser', ['CurrentUser', function(CurrentUser) {
  return function(scope, element, attrs) {
    CurrentUser.name = attrs.name;
  };
}]);

html

<div ng-app="app">
  <div class="view-container">
    <div ng-view currentuser name="testusername" class="view-frame animate-view"></div>
  </div>
</div>

在此解决方案中,CurrentUser是一项服务,可以将其注入任何控制器中,然后提供.name属性。

两个注意事项:

  • 我遇到的一个问题是控制器加载后设置了.name,因此,作为解决方法,在控制器范围内呈现用户名之前,我的超时时间很短。是否有一种整洁的方式等待服务上设置.name?

  • 这看起来像是一种非常简单的方法,可以将所有身份验证保存在Angular之外,从而使当前用户进入Angular App。您可以使用一个before_filter来防止未登录的用户进入Angular应用程序引导所在的html,并且在该html中,如果您想与用户的详细信息进行交互,则可以插值已登录用户的名称甚至其ID。通过来自Angular应用的http请求。您可以允许未登录的用户与默认的“来宾用户”一起使用Angular App。关于为什么这种方法不好的任何建议都将受到欢迎-感觉太容易了!

这是@Michael Tiller出色回答的扩展他的回答是通过将$attrs对象注入到控制器中来初始化视图中的变量如果$routeProvider通过路由导航时调用了同一控制器,则会出现问题然后,您将获得注入器错误,Unknown provider : $attrsProvider因为$attrs仅在编译视图时才可进行注入。解决方案是$routeParams从路由初始化控制器时通过传递变量(foo)$attrs初始化控制器时从视图初始化控制器这是我的解决方案。

从路线

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

这会处理一个网址,例如'/mypage/bar'如您所见,foo是通过url参数传递的,并且我们为foo提供了$injector一个空白对象,$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'

});
本文地址:http://javascript.askforanswer.com/ninkeyizaichuangjianshijiangcanshuchuandigeiangularjskongzhiqima.html
文章标签: ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!