【问题标题】:Angular state resolve not injecting into controller角状态解析不注入控制器
【发布时间】:2016-09-21 22:38:29
【问题描述】:

我正在尝试让 ui-router 决定将其值传递给控制器​​ portalsForUserCtrl

这是路由器:

(function () {
'use strict';

var myApp = angular.module("myApp", ["common.services", "ui.router", 'ngMessages']);

    myApp.config(["$stateProvider", "$urlRouterProvider",
    function ($stateProvider, $urlRouterProvider) {
        $urlRouterProvider.otherwise("/");

        $stateProvider
            .state("portalsForUser", {
                url: "/userPortal/portalsForUser/:id",
                templateUrl: "app/userPortal/portalsForUser.html",
                controller: "portalsForUserCtrl as vm",
                resolve: {
                    userPortalService: "userPortalService",
                    portalsForUser: function (userPortalService, $stateParams) {
                        var userId = $stateParams.id;
                        console.log(userId);  //shows userId correctly
                        return userPortalService.getPortalsForUserPromise(userId)
                            .then(function (response) {
                                var userPortals = response.data;
                                console.log("userPortals", userPortals); //shows portals
                                return userPortals;
                            });
                    }
                }
            })
    }]
);

这是整个控制器:

(function () {
"use strict";

angular.module("myApp")
  .controller("portalsForUserCtrl", portalsForUserCtrl);

  portalsForUserCtrl.$inject = ['portalsForUser', 'userPortalService'];

  function portalsForUserCtrl(portalsForUser, userPortalService) {
    console.log("in portalsForUserCtrl");
    var vm = this;
    vm.portalsForUser = portalsForUser;
    console.log(portalsForUser);
  }

}());

在 index.html 的控制器 mainCtrl 中,我调用:

$state.go("portalsForUser", ({ "id": userId }));

这里是视图app/userPortal/portalsForUser.html的代码:

<div class="container">
    <table class="table table-condensed table-striped table-bordered">
    <tbody>
        <tr>
            <th class="col-md-2">&nbsp;</th>
            <th class="col-md-4">
                Portal Name
            </th>
        </tr>

        <tr ng-repeat="userPortal in vm.portalsForUser">
            <td>
                {{userPortal.portal.portalName}}
            </td>
            <td class="">
                <a class="btn btn-primary" ui-sref="goSomewhere({id: userPortal.portal.id})">
                    Go
                </a>
            </td>
        </tr>
    </tbody>
</table>

这是 userPortalService 的代码:

(function () {
"use strict";

angular.module("myApp")
    .service('userPortalService', userPortalService);

userPortalService.$inject = ['userPortalResource', '$http', 'appSettings']

  function userPortalService(userPortalResource, $http, appSettings) {

    var getPortalsForUserPromise = function (id) {
        return $http.get(appSettings.serverPath + '/api/UserPortal/GetPortalsForUser/' + id);
    };

    return {
        getPortalsForUserPromise: getPortalsForUserPromise
    };
  }

}());

网址更改为正确的/userPortal/portalsForUser/:id,但portalsForUserCtrl 函数未触发。 只有当我在同一个 url 上按 enter 时才会实例化 portalsForUserCtrl 并且数据才会出现在视图中。我错过了什么?

【问题讨论】:

  • 您的控制台有错误吗?我也认为没有必要在你的解析块中userPortalService: "userPortalService"
  • 控制台中没有错误。删除您提到的行没有任何效果,所以您是正确的,不需要它,谢谢但是,更改并没有解决我的问题。

标签: javascript angularjs angular-ui-router


【解决方案1】:

$state.go 语句中有语法错误。

改变这个:

$state.go("portalsForUser", ({ "id": userId }));.

到这里:

$state.go("portalsForUser", { "id": userId });

【讨论】:

  • 很好,谢谢,但更改没有效果。仍然使用正确的 stateParam 到达“resolve”块。
  • 尝试在 then 块之后也写入 catch 块,如果有的话,控制台记录错误。另外,您在console.log("userPortals", userPortals); 上解决了什么问题?
  • 添加了catch块,但是没有报错。在 console.log 中,我看到了 userPortals,所以它们被返回就好了。问题仍然是它们没有被注入控制器。
  • 我认为你不需要 portalsForUserCtrl.$inject = ['portalsForUser', 'userPortalService']; 请删除它并检查
  • 删除它没有效果——结果相同。如果没有注入或传递给构造函数,portalsForUserCtrl 将如何获取依赖项?
【解决方案2】:

在文档 (https://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$stateProvider) 中,该方法的规范提到了以下内容:

地图对象是:

key - {string}:要注入控制器的依赖名称 factory - {string|function}:如果是字符串,那么它是服务的别名。 否则,如果是函数,则将其注入并返回将其视为的值 依赖。如果结果是一个承诺,它会在它的值是之前解决 注入控制器。

以以下为例:

resolve: {
    myResolve1:
        function($http, $stateParams) {
          return $http.get("/api/foos/"+stateParams.fooID);
        }
    }

因此,我建议您将代码更改为以下选项之一,以使其尽可能简单,并使用 chrome 开发人员工具,在方法的第一行放置一个断点:

resolve: {
    portalsForUser: ['userPortalService', '$stateParams', function (userPortalService, $stateParams) {
        var userId = $stateParams.id; //place your breakpoint here
        return userPortalService.getPortalsForUserPromise(userId);
    }] 
}

检查 $stateParams 发生了什么;出于某种原因,此时一切都还没有初始化,因为值不是来自 url,这并非不可能,因此 id 属性是未定义的。尝试注入 "$state" 并查看 $state.params.id 是否包含您期望的内容。 (就像这里提到的:https://angular-ui.github.io/ui-router/site/#/api/ui.router.state.$state)。 下面是它的样子:

resolve: {
    portalsForUser: ['userPortalService', '$state', function (userPortalService, $state) {
        var userId = $state.params.id; //place your breakpoint here
        return userPortalService.getPortalsForUserPromise(userId);
    }] 
}

希望如果它不能解决你的问题,至少它会帮助你找到它。

编辑:

看来之前的一切都没有朝着正确的方向发展。

这是我的新方向: 我使用您的 plunker 在我的计算机上创建了一个托管站点(使用 http-server:https://www.npmjs.com/package/http-server)。我的版本似乎与您的版本差别不大。完整代码如下:

app.js:

(function () {
    'use strict';

    var myApp = angular.module("myApp", ["ui.router"]);

    myApp
        .config(config)
        .controller("portalsForUserCtrl", portalsForUserCtrl)
        .service('userPortalService', userPortalService)
        .controller("mainCtrl", mainCtrl)

    mainCtrl.$inject = ["userPortalService", "$state"];

    function mainCtrl(userPortalService, $state) {
        var vm = this;

        vm.clickMe = function () {
          var userId = 1;
            $state.go("portalsForUser", { "id": userId });
        }
    };

    config.$inject=["$stateProvider"];

    function config($stateProvider) {
            $stateProvider
                // PortalsForUser GET
                .state("portalsForUser", {
                    url: "/userPortal/portalsForUser/:id",
                    templateUrl: "portalsForUser.html",
                    controller: "portalsForUserCtrl as vm",
                    resolve: {
                        portalsForUser: ['userPortalService', '$stateParams', function (userPortalService, $stateParams) {
                            return userPortalService.getPortalsForUserPromise($stateParams.id).then(function(response){return response.data;});
                        }]
                    }
                })
        }

    userPortalService.$inject = ['$http', '$q', '$timeout']

    function userPortalService($http, $q, $timeout) {
        var getPortalsForUserPromise = function (id) {
            var myId=id;
            var deferred=$q.defer();

            $timeout(function(){
                deferred.resolve({data:[
                    {
                    id: 16,
                    portal: {
                        portalName: "Portal1-" + myId,
                        portalId: 1
                    }
                    },
                    {
                    id: 17,
                    portal: {
                        portalName: "Portal2-" + myId,
                        portalId: 2
                    }
                    }
                ]});
            },5000);
            return deferred.promise;
        };

        return {
            getPortalsForUserPromise: getPortalsForUserPromise
        };
    };

    portalsForUserCtrl.$inject = ['portalsForUser', 'userPortalService'];

    function portalsForUserCtrl(portalsForUser, userPortalService) {
        console.log("in portalsForUserCtrl");
        var vm = this;
        vm.portalsForUser = portalsForUser;
        console.log(portalsForUser);
    };
}());

index.html:

<html>
    <head></head>
</html>
<body ng-app="myApp">
    <!-- bower:js -->
    <script src="/bower_components/angular/angular.js"></script>
    <script src="/bower_components/angular-ui-router/release/angular-ui-router.js"></script>
    <!-- endbower -->

    <!-- inject:js -->
    <script src="app.js"></script>
    <!-- endinject -->
    <body ng-app="myApp" ng-controller="mainCtrl as vm">
        <button type="submit" class="btn btn-default" ng-click="vm.clickMe()">
            Click Me
        </button>
        <div ui-view></div>
    </body>
</body>

portalsForUser.html:

<div class="container">
    Portals For User
    <table class="table table-condensed table-striped table-bordered">
        <tbody>
            <tr>
                <th class="col-md-2">&nbsp;</th>
                <th class="col-md-4">
                    Portal Name
                </th>
            </tr>

            <tr ng-repeat="userPortal in vm.portalsForUser">
                <td>
                    {{userPortal.portal.portalName}}
                </td>
                <td class="">
                    <a class="btn btn-primary" ui-sref="goSomewhere({id: userPortal.portal.id})">
                        Go
                    </a>
                </td>
            </tr>
        </tbody>
    </table>

</div>

bower.json

{
  "name": "test",
  "description": "just a test",
  "main": "index.js",
  "authors": [
    "me"
  ],
  "license": "ISC",
  "homepage": "index.html",
  "private": true,
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
    "angular": "^1.5.8",
    "angular-ui-router": "ui-router#^0.3.1"
  }
}

我按照其他人的建议在 index.html 中添加了 div ui-view,但我相信这已经在您的初始项目中了。 我还尝试像真实的服务一样模拟服务(使用承诺和属性数据)。

你确定你有正确的 ui-router 和 angular 版本吗?

【讨论】:

  • 我已将 console.log 行添加到 .state 条目的源代码中,以显示 $stateParams 正确返回了 userId。
  • 你能为此做一个plunker吗?我们不可能猜到这里发生了什么......
  • 你有没有从一开始就尝试重做一个完整的承诺? var def= $q.defer();并在回调中: def.resolve(userPortals) 而不是“return userPortals”
  • Plunker 位于 plnkr.co/edit/5sLccH5N6hZILfv1FR6k?p=info 如果需要其他任何东西,请告诉我。
  • 问题是我在 index.html 中有一个
    块。由于我未包含的代码错误,未设置 isLoggedIn 值。我现在正在解决这个问题。你的回答是最有帮助的,如果不是完全正确的话。所以我会给你赏金。制作 plunker 也是个好主意。我再问一个问题:如果 isLoggedIn 值为 false,是否意味着 portalsForUserCtrl 不会实例化?好像是这样的。
【解决方案3】:

依赖注入可能存在问题。试试这个 -

resolve: {
           portalsForUser: ['userPortalService', '$stateParams', function (userPortalService, $stateParams) {
           var userId = $stateParams.id;
                 return userPortalService.getPortalsForUserPromise(userId)
                        .then(function (response) {
                            var userPortals = response.data;
                            console.log("userPortals", userPortals);
                            return userPortals;
                        });
                }] 
          }

【讨论】:

  • 我试过这个@Kalyan,但它并没有解决问题。我仍然必须按 才能使数据出现在视图中。
【解决方案4】:

根据您的代码,我发现您的控制器与模块 clubSkedApp 相关联,而您的配置与 myApp 模块相关联。

对两者使用相同的模块,或者像这样包含控制器的模块。

var myApp = angular.module("myApp", ["clubSkedApp","common.services", "ui.router", 'ngMessages']);

另一种方法是检查未加载状态的原因。 ui-router 不好引发错误,我发现检查路由更改中的错误的唯一方法如下:

myApp.run(runFn);

runFn.$inject = ['$rootScope'];

function runFn($rootScope){

  //Show the errores caused by the resolve function
  $rootScope.$on('$stateChangeError', function (event, toState, toParams, 
    fromState, fromParams, error) {
      event.preventDefault();
      console.log(error);
    });
}

【讨论】:

  • $stateChangeError 是个好主意。但是,就我而言,它没有显示任何错误。
  • 模块名称怎么样,您是否尝试将模块名称更改为控制器定义?
【解决方案5】:

我知道问题所在。解决方案非常简单。

您需要在 index.html 中添加&lt;div ui-view&gt;&lt;/div&gt; 以在稍后的状态下显示您的视图,如下面的代码。

  <body ng-app="myApp" ng-controller="mainCtrl as vm">
    <button type="submit" class="btn btn-default" ng-click="vm.clickMe()">
        Click Me
    </button>
    <div ui-view></div>
  </body>

更多详情

【讨论】:

    猜你喜欢
    • 2015-03-10
    • 1970-01-01
    • 2022-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多