2014-05-06 30 views
5

Có thể chuyển lời hứa đến giao diện người dùng.Xác lý số $state từ bộ điều khiển bên ngoài (ví dụ: bộ điều khiển kích hoạt trạng thái) không?Vượt qua lời hứa thành bộ điều khiển trạng thái Giao diện người dùng góc-

Tôi biết rằng $state.go() trả về lời hứa; có thể ghi đè lên số rằng với lời hứa của riêng bạn tự giải quyết trực tiếp lời hứa này hoặc giải quyết nó bằng lời hứa mới không?

Ngoài ra, tài liệu cho biết lời hứa trả về $state.go() có thể bị từ chối với lời hứa khác (được chỉ ra bởi transition superseded), nhưng tôi không thể tìm thấy bất kỳ nơi nào cho biết điều này có thể được thực hiện từ bên trong chính nhà nước.

Ví dụ: trong mã bên dưới, tôi muốn có thể đợi người dùng nhấp vào nút ($scope.buttonClicked()) trước khi tiếp tục đến doSomethingElse().

Tôi biết rằng tôi có thể phát ra một sự kiện, nhưng vì lời hứa được nướng thành Angular rất sâu, tôi tự hỏi liệu có cách nào để thực hiện điều này thông qua promise.resolve/promise.reject.

angular.module('APP', ['ui.router']) 
.config(['$stateProvider', function ($stateProvider) { 
    $stateProvider 
    .state('myState', { 
     template: '<p>myState</p>', 
     controller: ['$state', '$scope', '$q', function ($state, $scope, $q) { 
      var deferred = $q.defer(); 

      $scope.buttonClicked = function() { 
       deferred.resolve(); 
      } 
     }] 
    }); 
}]) 
.controller('mainCtrl', ['$state', function ($state) { 
    $state.go('myState') 
    .then(doSomethingElse) 
}]); 

Cập nhật Tôi đã chấp nhận câu trả lời @ blint như nó đã khiến tôi gần gũi nhất với những gì tôi muốn. Dưới đây là một số mã xác định ý tưởng của câu trả lời này thêm một chút nữa. Tôi không nghĩ rằng cách tôi đã viết này là một giải pháp rất thanh lịch và tôi hạnh phúc nếu ai đó có thể đề xuất một cách tốt hơn để giải quyết lời hứa từ một trạng thái kích hoạt.

Giải pháp mà tôi đã chọn là kết chuỗi các lời hứa như bình thường trong bộ điều khiển của bạn, nhưng để lại phương thức $scope.next() (hoặc thứ gì đó tương tự) gắn với phạm vi đó giải quyết/từ chối lời hứa. Kể từ khi nhà nước có thể kế thừa phạm vi của bộ điều khiển cuộc gọi, nó sẽ có thể gọi phương thức đó trực tiếp và do đó giải quyết/từ chối lời hứa. Dưới đây là làm thế nào nó có thể làm việc:

Thứ nhất, thiết lập trạng thái của bạn với các nút/bộ điều khiển mà gọi một phương thức $scope.next():

.config(function ($stateProvider) { 
    $stateProvider 
    .state('selectLanguage', { 
     template: '<p>Select language for app: \ 
      <select ng-model="user.language" ng-options="language.label for language in languages">\ 
       <option value="">Please select</option>\ 
      </select>\ 
      <button ng-click="next()">Next</button>\ 
      </p>', 
     controller: function ($scope) { 
      $scope.languages = [ 
       {label: 'Deutch', value: 'de'}, 
       {label: 'English', value: 'en'}, 
       {label: 'Français', value: 'fr'}, 
       {label: 'Error', value: null} 
      ]; 
     } 
    }) 
    .state('getUserInfo', { 
     template: '<p>Name: <input ng-model="user.name" /><br />\ 
      Email: <input ng-model="user.email" /><br />\ 
      <button ng-click="next()">Next</button>\ 
      </p>' 
    }) 
    .state('mainMenu', { 
     template: '<p>The main menu for {{user.name}} is in {{user.language.label}}</p>' 
    }) 
    .state('error', { 
     template: '<p>There was an error</p>' 
    }); 
}) 

Tiếp theo, bạn thiết lập điều khiển của bạn. Trong trường hợp này, tôi đang sử dụng một phương pháp dịch vụ địa phương, user.loadFromLocalStorage() để có được bóng lăn (nó trả về một lời hứa), nhưng bất kỳ lời hứa sẽ làm. Trong quy trình làm việc này, nếu $scope.user thiếu bất kỳ thứ gì, nó sẽ dần dần được điền bằng các trạng thái. Nếu nó được điền đầy đủ, nó sẽ bỏ qua ngay menu chính. Nếu các phần tử bị để trống hoặc đang ở trạng thái không hợp lệ, bạn sẽ được đưa đến chế độ xem lỗi.

.controller('mainCtrl', function ($scope, $state, $q, User) { 
    $scope.user = new User(); 

    $scope.user.loadFromLocalStorage() 
    .then(function() { 
     var deferred; 

     if ($scope.user.language === null) { 
      deferred = $q.defer(); 

      $state.go('selectLanguage'); 

      $scope.next = function() { 
       $scope.next = undefined; 

       if ($scope.user.language === null) { 
        return deferred.reject('Language not selected somehow'); 
       } 

       deferred.resolve(); 
      }; 

      return deferred.promise; 
     } 
    }) 
    .then(function() { 
     var deferred; 

     if ($scope.user.name === null || $scope.user.email === null) { 
      deferred = $q.defer(); 

      $state.go('getUserInfo'); 
      $scope.next = function() { 
       $scope.next = undefined; 

       if ($scope.user.name === null || $scope.user.email === null) { 
        return deferred.reject('Could not get user name or email'); 
       } 

       deferred.resolve(); 
      }; 

      return deferred.promise; 
     } 


    }) 
    .then(function() { 
     $state.go('mainMenu'); 
    }) 
    .catch(function (err) { 
     $state.go('error', err); 
    }); 

}); 

Điều này là khá dài và chưa đủ, nhưng nó thể hiện ý định chung của điều khiển luồng không đồng bộ bằng lời hứa.

+0

Bạn có ý gì khi 'có thể ghi đè điều đó bằng lời hứa của riêng bạn? '? – blint

+0

Xin lỗi. Tôi đoán cách tốt hơn để nói đó là, bạn có thể giải quyết một lời hứa '$ state' với lời hứa của riêng bạn. – Andrew

Trả lời

3

Mục đích của promises là để đảm bảo kết quả ... hoặc xử lý lỗi. Lời hứa có thể được xích lại, trả về chức năng và do đó được mở rộng.

Bạn sẽ không quan tâm đến việc "ghi đè" lời hứa. Tuy nhiên, bạn có thể làm những gì:

  • Xử lý trường hợp lỗi.Dưới đây là các ví dụ từ các tài liệu:
promiseB = promiseA.then(function(result) { 
    // success: do something and resolve promiseB 
    //   with the old or a new result 
    return result; 
    }, function(reason) { 
    // error: handle the error if possible and 
    //  resolve promiseB with newPromiseOrValue, 
    //  otherwise forward the rejection to promiseB 
    if (canHandle(reason)) { 
    // handle the error and recover 
    return newPromiseOrValue; 
    } 
    return $q.reject(reason); 
    }); 
  • Nối một hoạt động không đồng bộ mới trong chuỗi lời hứa. Bạn có thể kết hợp lời hứa. Nếu một phương pháp được gọi trong chuỗi trả về một lời hứa, phụ huynh đã hứa sẽ treo phần còn lại của chuỗi khi lời hứa mới được giải quyết.

Dưới đây là mô hình bạn có thể tìm kiếm:

angular.module('APP', ['ui.router']) 
.config(['$stateProvider', function ($stateProvider) { 
    $stateProvider 
    .state('myState', { 
     template: '<p>myState</p>', 
     controller: 'myCtrl' 
    }); 
}]) 
.controller('myCtrl', ['$scope', '$state', '$q', '$http', 'someAsyncServiceWithCallback', 
    function ($scope, $state, $q, $http, myService) { 
    $scope.buttonClicked = function() { 
     $state.go('myState') 
     .then(function() { 
      // You can return a promise... 
      // From a method that returns a promise 
      // return $http.get('/myURL'); 

      // Or from an old-school method taking a callback: 
      var deferred = $q.defer(); 
      myService(function(data) { 
       deferred.resolve(data); 
      }); 

      return deferred.promise; 
     }, 
     function() { 
      console.log("$state.go() failed :("); 
     }); 
    }; 
}]); 
+0

Rất độc đáo bằng văn bản. Một bình luận mặc dù, $ scope.buttenClicked giải quyết trì hoãn ở đó, điều này chỉ có thể xảy ra _once_ và các nhấp chuột tiếp theo sẽ đơn giản bị bỏ qua, tôi nghĩ rằng nó đáng làm rõ. –

+0

@BenjaminGruenbaum cũng đề cập đến điều này, nhưng lời hứa trả về từ '$ state.go ('myState')' trả về ngay lập tức (tốt, ngay khi trạng thái được kích hoạt và khung nhìn được cập nhật), không phải khi '$ scope. buttonClicked() 'được gọi. Đó là mối liên kết tôi hy vọng sẽ thực hiện. – Andrew

+0

Lời hứa trả về ngay lập tức, nhưng bạn chỉ có thể truy cập vào giá trị của họ (gọi là "unwrapping" lời hứa) thông qua '.then' –

1

Có lẽ một cách để đạt được điều này sẽ quay trở lại lời hứa của mình từ của tiểu bang resolve

resolve: { 
    myResolve: function($scope, $q) { 
     var deferred = $q.defer(); 
     $scope.buttonClicked = function() { 
      deferred.resolve(); 
     } 
     return deferred.promise; 
    } 
} 

Ngoài ra còn có một ví dụ trong resolve docs có thể quan tâm

// Another promise example. If you need to do some 
// processing of the result, use .then, and your 
// promise is chained in for free. This is another 
// typical use case of resolve. 
promiseObj2: function($http){ 
    return $http({method: 'GET', url: '/someUrl'}) 
     .then (function (data) { 
      return doSomeStuffFirst(data); 
     }); 
}, 
+0

Tôi vừa thử điều này, và nó rất gần với những gì tôi cần. Thật không may, '$ scope' không tồn tại trong khối' resolve' (tôi đoán nó tương đương với khối 'config'). Vì vậy, tôi không thể liên kết một hành động trong khuôn mẫu khung nhìn hoặc bộ điều khiển trạng thái với sự phụ thuộc 'resol'. – Andrew

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