问题
I'm having problems executing a breeze query with angular resolve before the view is rendered. I'm trying to get some data from the server before the view is rendered with breeze. I'm using
$routeProvider.when('/countries', { templateUrl: 'App/partials/countries.html', controller: Ctrl, resolve: Ctrl.resolve }).
controller and service snippets:
function Ctrl($scope, Q, datacontext, countries) {
//...
}
function getCountries(forceRefresh) {
var query = entityQuery.
from("countries").
orderBy("name");
return manager.executeQuery(query).
then(getSucceeded);
}
function getSucceeded(data) {
return data.results;
}
this makes my view never render:
Ctrl.resolve = {
countries: function (datacontext) {
return datacontext.getCountries();
}
}
whereas if I create a timer that takes longer time, it works. I've tried wrapping it with $q but I can't seem to get it to work.
this will render the view because of the timeout:
Ctrl.resolve = {
countries: function (datacontext) {
return datacontext.getCountries();
},
delay: function ($q, $timeout) {
var delay = $q.defer();
$timeout(delay.resolve, 6000);
return delay.promise;
}
}
If anyone can help me with this, it would be great. I'm not sure if I'm doing something wrong or if there are limitations with Q promises or breeze in resolve.
回答1:
I feel your pain. One of the mistakes in the $q/route resolve implementation is that the resolve does not honor the Q.then
method. That violates the generally accepted practice of supporting interchangeable promise implementations (sigh).
But that's not the real problem. The real problem is that Angular doesn't know when your async method is resolved. You have to call $rootScope.$apply
manually in both success and failure callbacks. Angular's $http and $q do this (or equivalent) for you. Getting it right yourself is a PITA.
As I said, we feel your pain. Very soon we will release a tiny Q plug-in that converts a Q promise to $q promise and should alleviate that pain. At least it does for me :-).
In a nutshell, find a place near where your app starts and extend Q something like this:
angular.module('app').factory('util', ['$q', '$rootScope', util]); function util($q, $rootScope) { extendQ(); ... other utilities here ... // Monkey patch to$q method into Q.js' promise prototype // ex usage: return manager.executeQuery(qry).to$q(succ, fail); function extendQ() { var promise = Q.defer().promise; var fn = Object.getPrototypeOf(promise); if (fn.to$q) return; // already extended fn.to$q = function (success, fail) { return to$q(this, success, fail); }; } function to$q(qPromise, success, fail) { var d = $q.defer(); qPromise .then(function (data) { if (data === undefined) { logger.logError("Programming error: no data. " + "Perhaps success callback didn't return a value or " + "fail callback didn't re-throw error"); // If an error is caught and not re-thrown in an earlier promise chain // you will arrive here with data === undefined. // Neglecting to re-throw is a common, accidental omission. // To be safe, have every success callback return something // and trap here if data is ever undefined } d.resolve(data); $rootScope.$apply();// see https://groups.google.com/forum/#!topic/angular/LQoBCQ-V_tM }) .fail(function (error) { d.reject(error); $rootScope.$apply();// see https://groups.google.com/forum/#!topic/angular/LQoBCQ-V_tM }); if (success || fail) { d.promise = d.promise.then(success, fail); } return d.promise; }
Now use it like this (based on your example):
function getCountries() { var query = breeze.EntityQuery.from("countries").orderBy("name"); return manager.executeQuery(query).to$q(getSucceeded); function getSucceeded(data) { return data.results; } }
Addendum
I have been asked:
"Why so complicated? Why don't you use $q.when(qPromse)
to convert Q promise to $q promise?"
I tried that ... and couldn't make it work. Specifically, I tried this:
function to$q(qPromise, success, fail) { var promise = $q.when(qPromise); if (success || fail) { promise = promise.then(success, fail); } return promise; }
I believe there is something wrong with $q.when
.
来源:https://stackoverflow.com/questions/17724519/resolving-breeze-query-q-promise-with-route-resolve-stops-page