簡體   English   中英

具有解析功能的 Angularjs ng-controller

[英]Angularjs ng-controller with resolve

我遇到了 ng-controller 和“解決”功能的問題:

我有一個控制器需要在運行之前解決一些依賴關系,當我通過 ng-route 定義它時它工作正常:

控制器代碼如下所示:

angular.module('myApp')
  .controller('MyController', ['$scope', 'data', function ($scope, data) {
      $scope.data = data;
    }
  ]
);

路由:

...
.when('/someUrl', {
        templateUrl : 'some.html',
        controller : 'MyController',
        resolve : {
          data: ['Service', function (Service) {
            return Service.getData();
          }]
        }
})
...

當我去 /someUrl 時,一切正常。

但是我需要以其他方式使用這個控制器(我需要在不同的地方使用這兩種方式):

<div ng-controller="MyController">*some html here*</div>

而且,當然,它失敗了,因為“數據”依賴沒有得到解決。 當我使用“ng-controller”或者我應該放棄並在控制器內加載數據時,有什么方法可以將依賴項注入控制器?

在下面,對於路由解析,我們正在解析承諾並將返回數據包裝在具有屬性的對象中。 然后,我們在用於 ng-controller 表單的包裝器服務 ('dataService') 中復制此結構。

包裝服務也解析承諾,但在內部這樣做,並更新我們已經返回以供控制器使用的對象上的屬性。

在控制器中,如果你想延遲一些額外的行為,直到一切都得到解決並且數據可用之后,你可能會在這個屬性上放置一個觀察者。

或者,我已經演示了使用“包裝”另一個控制器的控制器; 一旦來自 Service 的承諾被解析,它就會將自己的 $scope 傳遞給包裝的控制器以及來自 Service 的現在解析的數據。

請注意,我已使用 $timeout 為承諾返回提供 1000 毫秒的延遲,以嘗試使其更清楚發生什么以及何時發生。

 angular.module('myApp', ['ngRoute']) .config(function($routeProvider) { $routeProvider .when('/', { template: '<h1>{{title}}</h1><p>{{blurb}}</p><div ng-controller="ResolveController">Using ng-controller: <strong>{{data.data}}</strong></div>', controller: 'HomeController' }) .when('/byResolve', { template: '<h1>{{title}}</h1><p>{{blurb}}</p><p>Resolved: <strong>{{data.data}}</strong></p>', controller: "ResolveController", resolve: { dataService: ['Service', function(Service) { // Here getData() returns a promise, so we can use .then. // I'm wrapping the result in an object with property 'data', so we're returning an object // which can be referenced, rather than a string which would only be by value. // This mirrors what we return from dataService (which wraps Service), making it interchangeable. return Service.getData().then(function(result) { return { data: result }; }); } ] } }) .when('/byWrapperController', { template: '<h1>Wrapped: {{title}}</h1><p>{{blurb}}</p><div ng-controller="WrapperController">Resolving and passing to a wrapper controller: <strong>{{data.data ? data.data : "Loading..."}}</strong></div>', controller: 'WrapperController' }); }) .controller('HomeController', function($scope) { $scope.title = "ng-controller"; $scope.blurb = "Click 'By Resolve' above to trigger the next route and resolve."; }) .controller('ResolveController', ['$scope', 'dataService', function($scope, dataService) { $scope.title = "Router and resolve"; $scope.blurb = "Click 'By ng-controller' above to trigger the original route and test ng-controller and the wrapper service, 'dataService'."; $scope.data = dataService; } ]) .controller('WrapperController', ['$scope', '$controller', 'Service', function($scope, $controller, Service) { $scope.title = "Resolving..."; //this controller could of course not show anything until after the resolve, but demo purposes... Service.getData().then(function(result) { $controller('ResolveController', { $scope: $scope, //passing the same scope on through dataService: { data: result } }); }); } ]) .service('Service', ['$timeout', function($timeout) { return { getData: function() { //return a test promise return $timeout(function() { return "Data from Service!"; }, 1000); } }; } ]) // our wrapper service, that will resolve the promise internally and update a property on an object we can return (by reference) .service('dataService', function(Service) { // creating a return object with a data property, matching the structure we return from the router resolve var _result = { data: null }; Service.getData().then(function(result) { _result.data = result; return result; }); return _result; });
 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.27/angular.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.27/angular-route.min.js"></script> <div ng-app="myApp"> <a href="#/">By ng-controller</a> | <a href="#/byResolve">By Resolve</a> | <a href="#/byWrapperController">By Wrapper Controller</a> <div ng-view /> </div>

創建一個新模塊,您可以在其中注入服務,如下所示。

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

module.service('userService', function(Service){
    return Service.getData();
});

在你的應用模塊中注入新創建的服務模塊

angular.module('myApp')
  .controller('MyController', ['$scope', 'myservice', function ($scope, myservice) {
      $scope.data = data;
    // now you can use new dependent service anywhere here.
    }
  ]
);

您可以使用原型的機制。

.when('/someUrl', {
    template : '<div ng-controller="MyController" ng-template="some.html"></div>',
    controller: function (data) { 
        var pr = this;
        pr.data = data;
    },
    controllerAs: 'pr',
    resolve : {
        data: ['Service', function (Service) {
            return Service.getData();
        }]
    }
})

angular.module('myApp')
  .controller('MyController', ['$scope', function ($scope) {
      $scope.data = $scope.pr.data; //magic
    }
  ]
);

現在無論你想使用

'<div ng-controller="MyController"></div>'

您需要確保調用控制器的 Scope 中有 pr.data。 以 uib-modal 為例

var modalInstance = $modal.open({
    animation: true,
    templateUrl: 'modal.html',
    resolve: {
        data: ['Service', function (Service) {
            return Service.getData();
        }]
    },
    controller: function ($scope, $modalInstance, data) { 
        var pr = this;
        pr.data = data;
        pr.ok = function () {
            $modalInstance.close();
        };
    },
    controllerAs:'pr',
    size:'sm'
});

模態.html

<script type="text/ng-template" id="modal.html">
    <div class="modal-body">
        <div ng-include="some.html"  ng-controller="MyController"></div>
    </div>
    <div class="modal-footer">
        <button class="btn btn-primary pull-right" type="button" ng-click="pr.ok()">{{ 'ok' | capitalize:'first'}}</button>
    </div>
</script>

現在你可以使用 $scope.data = $scope.pr.data; 在我的控制器中

pr.data 是我的風格。 您可以在沒有 PR 的情況下重寫代碼。 本視頻中描述的使用 ng-controller 的基本原理https://egghead.io/lessons/angularjs-the-dot

假設 Service.getData() 返回一個承諾,MyController 也可以注入該服務。 問題是您想延遲運行控制器,直到承諾解決。 雖然路由器會為您執行此操作,但直接使用控制器意味着您必須構建該邏輯。

angular.module('myApp')
  .controller('MyController', ['$scope', 'Service', function ($scope, Service) {
    $scope.data = {}; // default values for data 
    Service.getData().then(function(data){
      // data is now resolved... do stuff with it
      $scope.data = data;
    });
  }]
);

現在這在直接使用控制器時效果很好,但是在您的路由示例中,您希望延遲渲染頁面直到數據得到解析,您最終將兩次調用 Service.getData()。 有幾種方法可以解決這個問題,比如讓 Service.getData() 為所有調用者返回相同的承諾,或者這樣的事情可能會完全避免第二次調用:

angular.module('myApp')
  .controller('MyController', ['$scope', '$q', 'Service', function ($scope, $q, Service) {
    var dataPromise,
      // data might be provided from router as an optional, forth param
      maybeData = arguments[3]; // have not tried this before
    $scope.data = {}; //default values
    // if maybeData is available, convert it to a promise, if not, 
    //    get a promise for fetching the data
    dataPromise = !!maybeData?$q.when(maybeData):Service.getData();
    dataPromise.then(function(data){
      // data is now resolved... do stuff with it
      $scope.data = data;
    });    
  }]
);

我試圖使用ng-init解決問題,但在 angularjs.org 上遇到以下警告

ngInit 唯一合適的用途是為 ngRepeat 的特殊屬性設置別名,如下面的演示所示。 除了這種情況,您應該使用控制器而不是 ngInit 來初始化范圍上的值。

所以我開始搜索類似ng-resolve東西,並遇到了以下線程:

https://github.com/angular/angular.js/issues/2092

上面的鏈接包含一個具有類似ng-resolve功能的演示小提琴。 我認為ng-resolve可以成為 angular 1.x 未來版本的一個功能。 現在我們可以使用上面鏈接中提到的指令。

路由解析中的“數據”將無法注入到路由提供者以外的激活控制器中。 它僅可用於路由提供程序中配置的視圖。

如果你想直接激活控制器的數據而不是路由提供者激活,你需要為它做一個黑客。

看看這個鏈接是否有幫助:

http://www.johnpapa.net/route-resolve-and-controller-activate-in-angularjs/

在“解析”屬性中獲取數據是路由 (routeProvider) 的功能,而不是控制器的功能。

鍵(是你的情況:'數據')在解析屬性被注入作為服務。 這就是我們能夠從該服務獲取數據的原因。

但是要在不同的地方使用相同的控制器,您必須在控制器中獲取數據。

嘗試這個

服務:

(function() {

var myService = function($http) {
    var getData = function() {
        //return your result
    };
    return {
        getData:getData
    };
};
var myApp = angular.module("myApp");
myApp.factory("myService", myService);
}());

控制器:

(function () {
var myApp = angular.module("myApp");
myApp.controller('MyController', [
    '$scope', 'myService', function($scope, myService) {
        $scope.data = myService.getData();
    }
]);

//Routing
.when('/someUrl', {
    templateUrl : 'some.html',
    controller : 'MyController',
    resolve : {
        data: $scope.data,
    }
})
}());

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM