2015-03-03 32 views
28

Khi ứng dụng của tôi bắt đầu tôi tải một số cài đặt từ một máy chủ. Hầu hết các bộ điều khiển của tôi cần điều này trước khi bất cứ điều gì hữu ích có thể được thực hiện. Tôi muốn đơn giản hóa mã của bộ điều khiển càng nhiều càng tốt. Nỗ lực của tôi không hoạt động, giống như sau:nhà máy kiễu góc trả lại một lời hứa

app.factory('settings', ['$rootScope', '$http', '$q', function($rootScope, $http, $q) { 
    var deferred = $q.defer(); 

    $http.get('/api/public/settings/get').success(function(data) { 
     $rootScope.settings = data; 
     deferred.resolve(); 
    }); 

    return deferred.promise; 
}]); 

app.controller('SomeCtrl', ['$rootScope', 'settings', function($rootScope, settings) { 
    // Here I want settings to be available 
}]); 

Tôi muốn tránh có nhiều cài đặt.

Bất kỳ ý tưởng về cách giải quyết này một cách thoải mái?

Trả lời

19

$ http bản thân trở lại hứa với bạn không cần phải ràng buộc nó bên trong $ q đây không phải là một thực hành tốt và được coi là chống Pattern.

Sử dụng: -

app.factory('settings', ['$rootScope', '$http', '$q', function($rootScope, $http) { 
     return $http.get('/api/public/settings/get') 
    }]); 

    app.controller('SomeCtrl', ['settings',$scope, function(settings,$scope) { 
     settings.then(function(result){ 
       $scope.settings=result.data; 
      }); 
    }]); 

cách của bạn có thể được thực hiện như sau: -

app.factory('settings', ['$rootScope', '$http', '$q', function($rootScope, $http, $q) { 
    var deferred = $q.defer(); 

    $http.get('/api/public/settings/get').success(function(data) { 
     deferred.resolve(data); 
    }); 

    return deferred.promise; 
}]); 

app.controller('SomeCtrl', ['$scope', 'settings', function($scope, settings) { 
    settings.then(function(data){ 
      $scope.settings=data; 
     }) 
}]); 

Đừng quá tải $ rootScope nếu bạn muốn nó, bạn cần phải sử dụng $ dõi những thay đổi trong $ rootScope (Không được khuyến nghị).

+1

Như tôi đã viết, tôi muốn tránh phần "settings.then". Lý tưởng nhất là tôi muốn bộ điều khiển SomeCtrl đợi cho đến khi cài đặt được tải. Điều đó có thể không? –

+0

bạn cần phải giải quyết nó bằng cách chỉ $ xem trong trường hợp đó trên $ rootScope.settings nhưng đó không phải là thực hành tốt (vấn đề permormance) kiểm tra bẩn và chu kỳ tiêu hóa mới sẽ làm chậm sự hoàn hảo. – squiroid

+0

Cảm ơn bạn đã chia sẻ phản hồi này. Đây là điều tuyệt vời cho tôi để làm cho chức năng dịch vụ của tôi tốt hơn và sạch hơn. – racl101

13

Một nơi nào đó bạn sẽ cần phải "chờ đợi".

duy nhất được xây dựng theo cách trong góc để hoàn toàn giải oan khiển từ phải chờ ngày của riêng mình cho dữ liệu async được nạp là để nhanh chóng một bộ điều khiển với tài sản resolve$routeProvider 's đường (hoặc thay thế $stateProvider của ui.router) . Điều này sẽ chạy bộ điều khiển chỉ khi tất cả các lời hứa được giải quyết, và dữ liệu được giải quyết sẽ được tiêm.

Vì vậy, ng-đường thay thế - plunker:

$routeProvider.when("/", { 
    controller: "SomeCtrl", 
    templateUrl: "someTemplate.html", 
    resolve: { 
    settings: function(settingsSvc){ 
     return settingsSvc.load(); // I renamed the loading function for clarity 
    } 
    }); 

Sau đó, trong SomeCtrl bạn có thể thêm settings như một sự phụ thuộc tiêm:

.controller("SomeCtrl", function($scope, settings){ 
    if (settings.foo) $scope.bar = "foo is on"; 
}) 

này sẽ "chờ" để tải someTemplate trong <div ng-view></div> cho đến khi cài đặt được giải quyết.

Các settingsSvc nên bộ nhớ cache lời hứa để nó sẽ không cần phải thực hiện lại các yêu cầu HTTP. Lưu ý, mà như đã đề cập trong câu trả lời khác, không có nhu cầu $q.defer khi API bạn đang sử dụng (như $http) đã trả về một lời hứa:

.factory("settingsSvc", function($http){ 
    var svc = {settings: {}}; 
    var promise = $http.get('/api/public/settings/get').success(function(data){ 
     svc.settings = data; // optionally set the settings data here 
    }); 
    svc.load = function(){ 
     return promise; 
    } 
}); 

Một cách tiếp cận, nếu bạn không thích những ngRoute , có thể là để phát sóng dịch vụ settings trên $rootScope một sự kiện khi cài đặt được tải và bộ điều khiển có thể phản ứng với nó và làm bất cứ điều gì. Nhưng điều đó có vẻ "nặng hơn" .then.

Tôi đoán cách thứ ba-plunker - sẽ có một bộ điều khiển ứng dụng cấp "cho phép" phần còn lại của ứng dụng chỉ khi tất cả các phụ thuộc đã cài đặt sẵn:

.controller("AppCtrl", function($q, settingsSvc, someOtherService){ 
    $scope.loaded = false; 
    $q.all([settingsSvc.load, someOtherService.prefetch]).then(function(){ 
     $scope.loaded = true; 
    }); 
}); 

Và trong Xem , chuyển đổi ng-if với loaded:

<body ng-controller="AppCtrl"> 
    <div ng-if="!loaded">loading app...</div> 

    <div ng-if="loaded"> 
    <div ng-controller="MainCtrl"></div> 
    <div ng-controller="MenuCtrl"></div> 
    </div> 
</body> 
1

Fo ui-router này có thể dễ dàng thực hiện với việc có một trạng thái gốc ứng dụng với độ nét tối thiểu ít nhất này

$stateProvider 
    .state('app', { 
     abstract: true, 
     template: '<div ui-view></div>' 
     resolve:  { 
      settings: function($http){ 
       return $http.get('/api/public/settings/get') 
          .then(function(response) {return response.data}); 
      } 
     } 
    }) 

Sau này bạn có thể làm cho tất cả các quốc gia ứng dụng kế thừa từ trạng thái gốc này và

  1. Tất cả các bộ điều khiển sẽ được thực hiện chỉ sau khi thiết lập được nạp
  2. Tất cả các bộ điều khiển sẽ được truy cập vào thiết lập giải quyết giá trị càng tốt.

Như đã đề cập ở trên quyết cũng làm việc cho bản gốc ng-đường nhưng vì nó không hỗ trợ làm tổ phương pháp này là không hữu ích như cho ui-router.

1

Bạn có thể tự bootstrap ứng dụng của bạn sau khi thiết lập được nạp.

var initInjector = angular.injector(["ng"]); 
var $http = initInjector.get("$http"); 
var $rootScope = initInjector.get("$rootScope"); 

$http.get('/api/public/settings/get').success(function(data) { 
    $rootScope.settings = data; 
    angular.element(document).ready(function() { 
     angular.bootstrap(document, ["app"]); 
    }); 
}); 

Trong trường hợp này, toàn bộ ứng dụng của bạn sẽ chỉ chạy sau khi cài đặt được tải.

Xem Angular bootstrap documentation để biết chi tiết

Các vấn đề liên quan