[英]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.