2017-03-08 3 views
0
$http.post('@Url.Action("donePressed")', 
{ 
    id: $scope.id, 
}).then(
function (response) // success callback 
{ 
    window.location = '@Url.Action("PdfCreator", "someController")?Id=' + $scope.id; 
    window.location='@Url.Action("Index","AnotherController")'; 
}, 
function (response) // failure callback 
{ 
    alert(response.statusText); 
}); 

Hallo, ich denke, ich tue somehting falsch, ich auf eine Funktion, die aufgerufen werden soll schickt mir eine Datei als Antwort, und anschliessend möchte ich die Seite verlassen und woanders hingehen . das Problem ist, weil dies eine Synchronisierung ist, bekomme ich meinen Download nicht.Datei herunterladen und dann verlassen Seite

Wie kann ich das synchronisieren?

Antwort

0

Async hat nichts damit zu tun. Sobald Sie sich im Erfolgsrückruf befinden, ist der Async-Teil bereits fertig. Das Problem ist, dass Sie den Fensterstandort erneut ändern, bevor die erste Änderung geladen werden konnte. Mit anderen Worten, es ist das genaue Gegenteil eines asynchronen Problems; Das Problem ist, dass dieser Code synchron ist und zu schnell läuft.

Allerdings ist der Ansatz hier zunächst fehlerhaft. Es könnte funktionieren, wenn der Browser gezwungen wurde, die Datei herunterzuladen, da die dann die erste Änderung an window.location selbst nicht die Browseransicht ändern würde. Da PDF in der Regel ein browsersichtbarer Typ ist, ist dies jedoch nicht garantiert. Unabhängig davon haben Sie immer noch das gleiche Problem, den zweiten Anruf zu verzögern, bis der erste eine Antwort bekommen hat, was grundsätzlich unmöglich ist. Es gibt kein eingebautes Ereignis für diese Art von Sache, also das Beste, was du tun könntest, wäre, setTimeout mit einer Verzögerung von 1-2 Sekunden zu verwenden, und hoffe nur, dass das genug Zeit ist, um die erste Antwort zu erhalten. Selbst wenn es jemals länger dauerte, würde Ihr Code wieder brechen. Mit anderen Worten, es wird extrem spröde.

Die einfache Tatsache ist, dass dies einfach nicht funktioniert, wie HTTP funktioniert. Sie versuchen im Grunde, zwei Antworten für eine einzelne Anfrage zurückzugeben, was nicht möglich ist. Dies ist ein cleverer Weg, um inhärente Einschränkungen des Protokolls zu umgehen, ich gebe Ihnen das, aber es ist letztlich immer noch unzureichend.

Alles, was Sie gesagt haben kann tatsächlich dies über die HTML5-Datei-API und AJAX passieren, aber Ihre Lösung wird dann nur mit modernen Browsern kompatibel sein (im Grunde alles außer IE 10 und darunter). Wenn Sie nicht weniger IE-Versionen unterstützen müssen, dann können Sie den folgenden Code verwenden statt:

function (response) // success callback 
{ 
    $http.get('@Url.Action("PdfCreator", "someController")?Id=' + $scope.id').then(
     function (response) // success callback 
     { 
      var a = document.createElement('a'); 
      var url = window.URL.createObjectURL(response.data); 
      a.href = url; 
      a.download = 'myfile.pdf'; 
      a.click(); 
      window.URL.revokeObjectURL(url); 
      window.location = '@Url.Action("Index","AnotherController")'; 
     }, 
     function (response) // failure callback 
     { 
      alert(response.statusText); 
     } 
    ); 
}, 

Die geheime Zutat ist das PDF über AJAX in Abrufen und dann ein Objekt URL aus den PDF-Daten zu schaffen. Sie können das verwenden, um ein Ankerelement im DOM zu erstellen und es "dynamisch" anzuklicken, um den Download zu starten. Der Nachteil ist jedoch, dass ich dies nicht mit Angular versucht habe, also bin ich mir nicht sicher, ob $http eine binäre Antwort unterstützt. Ich weiß mit jQuery, Sie müssen nur sagen, dass der Antworttyp des XHR-Objekts ist "Blob", aber ich bin mir nicht sicher, ob Sie oder wie Sie das gleiche mit Angular tun würden. Alternativ können Sie einfach XMLHttpRequest direkt für diesen bestimmten AJAX verwenden und einfach xhr.responseType = 'blob' einstellen.

Verwandte Themen