angular-pdfjs-viewer - Message: stream must have data - angularjs

I am struggling to get angular-pdfjs-viewer working in my angular app that's written in Typescript.
I am always getting a red error message with the text:
PDF.js v1.7.354 (build: 0f7548ba)
Message: stream must have data
The PDF data is coming from an ASP.NET WebAPI controller, and the architecture of our application has the front facing website and the API both deployed as two independent web applications.
Due to this, I am wanting to download the PDF in the angular controller, and set the PDF source to the data attribute of the directive.
The WebAPI returns the PDF like this:
[HttpGet]
[Route("invoice/{id}/originalpdf")]
public async Task<ActionResult> GetInvoiceSourceImagePdf(string id)
{
var userId = User.Identity.GetMyId();
var bytes = await _serviceThatReturnsByteArray(id);
return File(bytes, System.Net.Mime.MediaTypeNames.Application.Pdf);
}
I don't see an issue with the above. In the browser, if I hit this endpoint, I get the document rendering exactly as expected.
On the front-end side:
We're using the angular-pdfjs-viewer from https://github.com/legalthings/angular-pdfjs-viewer
We're including (via BundleConfig), sources in the order of: pdf.js, then angular.js and then finally angular-pdfjs-viewer.js (with other application required dependencies in between)
I am using the PDF.js dependency that "ships" with angular-pdfjs-viewer.js
The angular controller looks like this:
module MyApp {
class PdfDialogController {
public static $inject = ["$scope", "$window", "$log", "$uibModalInstance", "$http"];
pdfData: Uint8Array;
constructor(/*stuff*/){
this.$http.get(the_url, { responseType: 'arrayBuffer' })
.then((t) => {
this.pdfData = new Uint8Array(<ArrayBuffer>t.data);
});
}
}
}
And in the view, we have:
<div class="modal-body">
<div id="pdf-container">
<pdfjs-viewer data="vm.pdfData"></pdfjs-viewer>
</div>
</div>
Inspecting the network in the browser, the PDF content is downloaded.
t.data in the controller contains data that starts with
%PDF-1.3\n%����\n1 0 obj\n[/PDF /Text]
However, the views shows this:
And the console outputs an error message:
Error: An error occurred while loading the PDF.
What am I doing wrong, and how can I determine what the issue is with the PDF data (if there is one).

Well, it turns out that I was using
{ responseType: 'arrayBuffer' } // camel case
when I should be using
{ responseType: 'arraybuffer' } // all lowercase
Once changed, the code I posted in the question worked perfectly.

Related

Java, Struts 1.2, Json Angular JS - How can I get json response from action class to my Angular JS page?

I need a clarification on this below technology
Current technology:
Struts 1.2
Jsp
Java
AngularJS
Currently I am trying to migrate one of my jsp page to AngularJS page which is client req.
I am trying using below code to get json response, but I unable to get the json data in my jsp page.
Question:
1) How to get a json object from the response of action class in struts?
2) Currently :
Note: one of temporary way I able to get json object in jsp using session.setAttribute() and getAttribute.. but its not rite way to do it as I just getting all my table data and put in session. apart from this any way please help..
Code :
In jsp:
$scope.getDataFromServer = function() {
$http({
method : 'GET',
url : '/com/test/Browse.do'
}).then (function successCallback(response) {
var itemsDetails = JSON.parse(response);
$scope.person = response;
}).error(function(data, status, headers, config) {
});
};
**//The above response getting as object unable to get json object.**
In action class:
public void doExecute(ActionContext ctx) throws IOException,
ServletException {
PersonData personData = new PersonData();//[PersonData class available]
personData.setFirstName("Mohaideen");
personData.setLastName("Jamil");
String json = new Gson().toJson(personData);
ctx.forwardToInput();
}
I able to get the data using session attribute like below, but it is not rite way will make me to avoid struts action and also whole table data putting in session I not sure whether it will rite way or secure way.
var data1 = '<%=session.getAttribute("jsonobjtest")%>';
Can please help me out to get the rite way to implement with struts 1.2 and angularjs? if we cannot do it help me guide me the workaround how to achieve with angularjs?
Hie there from my understanding you want to get a json object from your Java backend
here is how i do http requests in AngularJs 1.5.11
(function () {
'use strict';
angular.module("myapp")
.controller("HelloController", function($scope,$http){
$scope.getDataFromServer = function() {
$http.get("/com/test/Browse.do").success(function(response,status){
//console.log(response,status); check your data
$scope.person = JSON.parse(response);
});
}
});

AngularJS 404 error on json file on GitHub Pages

I created a GitHub Pages project with AngularJS, the Angular content does not load from the json file, and I am getting a 404 error in the console:
Failed to load resource: the server responded with a status of 404 () birds.json
It is supposed to be just a client-side app. What is going on here? Does it have something to do with html5mode?
Repo
Demo
Related Questions:
Can one host an AngularJS based static blog on github?
AngularJS html5mode support on GitHub Pages
It's because your birds.json lies in the angular-birds directory. Try to change
var promise = $http.get('/birds.json').then(function (response) {
return response.data;
});
to
var promise = $http.get('angular-birds/birds.json').then(function (response) {
return response.data;
});
You may check out this AngularJS repository which I used to build and deploy my own website on github pages. Here is the demo.

How to successfully embed blob PDF response in IE11/Edge

I am not able to embed a blob url as an PDF in IE 11/Edge. There is a CORS issue and IE gives an 'Access Denied'. From my research on SO, I have realized that this is due to IE's inherent security restrictions. My question is is there any other way of taking the blob URL data response from the REST service and displaying it embedded in the browser. I want to avoid using any third party libraries.
The service returns as below:
function getTest(id) {
miEService.get(id)
.then(function (response) {
var fileUrl = URL.createObjectURL(response.data);
$scope.pdfData = $sce.trustAsResourceUrl(fileUrl);
});
get: function (id) {
var config = {
headers: {
accept: 'application/pdf'
}
, responseType: 'blob'
}
return $http.get(miEnv.services.eApi + '?$filter=id eq' +
' ' + id, config);
Finally inside the html the display is as below -
<object id="pdf" data={{$ctrl.pdfData}} type="application/pdf" width="100%" height="100%" alt="pdf" class="view-pdf_document">
If the rest service returns the binary data of the pdf, you could just embedd the url in your page as an Iframe rather than the binary content itself. It should render the pdf. If not, I've had success in the past just having the pdf be a link and when you click the link it opens the request to the rest service in a new tab. If the issue is that you don't want the rest service to show up in the url on the page, then you might have to proxy the request through your own server.

Aspnet Core. Angular. Static page and html5 mode

I am building AngularJs and WebApi application, usin Aspnet Core rc1. I have problem with returning static index.html file. I have tried several methods. The first method was to use such code in Startup.cs
app.UseFileServer();
app.UseMvc();
In this way it works, if I call http://localhost:29838 (root url). But if I go on http://localhost:29838/books ( /books root is my angular root defined using ng-route, and I am using html5 mode) and renew the page, server will return 404 mistake of course.
Then, I read this article https://dzone.com/articles/fixing-html5mode-and-angular .I have tried to use rewrite module method in web.config/ Everything works fine. But I do not like this method. As I have understood it works only with IIS.
Finally, I have tried to use the first way, described in article (when Home/Index returns html file).controller code is:
public ActionResult Index()
{
return File("~/index.html", "text/html");
}
and Startup.cs is:
routes.MapRoute(
name: "Default",
url: "{*.}",
defaults: new
{
controller = "Home",
action = "Index",
}
);
Using this approach I have such erros: Refused to load the script 'http://localhost:29838/libs/jquery/dist/jquery.min.js' because it violates the following Content Security Policy directive: "script-src 'unsafe-inline'". And I can not overcome this. What am I doing wrong?
Try to use AspnetCore.SpaServices, they provide you legit HTML5 spa-fallback.
Something like this:
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});
This library fix all your issues with SPA-fallback.
The SpaServices mentioned by #Andrei is great if you are using an MVC page that has server side render or some server logic.
If you don't have any logic in the server side, and you don't need it, you could just do the following:
app.Use(async (context, next) =>
{
await next();
if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value))
{
context.Request.Path = "/index.html";
await next();
}
})
.UseDefaultFiles(new DefaultFilesOptions { DefaultFileNames = new List<string> { "index.html" } })
.UseStaticFiles()
What the snippet does is look for pages that don't exist on the server side, and redirect them to '/index.html'. If you have a different entry point file, you may change the Url. Also, if the file requested has extension, it is served in order to allow javascript, css, html etc to be rendered on the client.
You can also take a look here: https://code.msdn.microsoft.com/How-to-fix-the-routing-225ac90f
Finally. I have found the solution. For security I use OpenIdConnect.Server. In sample project author used NWebsec.Middleware. And I have just copied csp settings from this sample project
app.UseCsp(options => options.DefaultSources(configuration => configuration.Self())
.ImageSources(configuration => configuration.Self().CustomSources("data:"))
.ScriptSources(configuration => configuration.UnsafeInline())
.StyleSources(configuration => configuration.Self().UnsafeInline()));
Notice, that authore misspelled calling .Self() method after ScripSources(). And I have not noticed that !!! Be carefull with copy and paste

Angular resource service does not consume rest ful service in rails (Json format)

I´m developing a web application where I have a front-end built with AngularJS that consumes Rest Services provided by a back-end API Rails application.
I would like to use the Angular $resource to get the Json objects in the backend API.
Client and Server applications run in different servers so far. So, angular client is in server-path:1234/app and backend api application runs in another-server-path:3000/.
Where server-path and another-server-path are localhost.
Both sides are developed, and works independently. I mean:
When I run another-server-path:3000/boats in a browser I get the list of boats, so the Restful service looks to be working.
I did a simulation in the client side, so, in my service I replaced the real url with a simulated url to a json data source. This code works too.
Now, I want to call the backend restful service in another-server-path:3000/boats from the angular service, but it´s now showing any data, neither I can see any get request in servers logs.
This is my angular service code:
angular.module('myApp.services', ['ngResource']).
// value('version', '0.1');
factory('Boat', function($resource){
return $resource('another-server-path:3000/:boatId', {}, {
query: {method:'GET', params:{boatId:'boats'}, isArray:true}
});
});
and this is my backend rails controller:
def index
#boats = Boat.all
respond_to do |format|
format.html
format.xml { render :xml => #boats}
format.json { render :json => #boats}
end
end
What am I missing? Please help.
UPDATE:
In Angular app, I changed my service file with:
return $resource('another-server-path\\:3000/:boatId', {}, {
query: {method:'GET', params:{boatId:'boats'}, isArray:true}
I also added this line to my app.js file:
delete $httpProvider.defaults.headers.common["X-Requested-With"];
and now I got the request in the api server. The controller is also executed. I got the boats from the DB. However I´m not able to send them back in JSON to Angular.
This is my api Controller:
def index
#boats = Boat.all
puts #boats
render :json => #boats
end
and this is the log I got when it´s called:
Started GET "/boats" for 127.0.0.1 at 2013-09-26 17:05:49 +0200
Processing by BoatsController#index as HTML
Boat Load (2.0ms) SELECT `boats`.* FROM `boats`
#<Boat:0x0000000675d9f0>
#<Boat:0x000000089e74a8>
#<Boat:0x000000089e71b0>
#<Boat:0x000000089e6e40>
Completed 200 OK in 66ms (Views: 3.0ms | ActiveRecord: 7.0ms)
As you can see, first, it says it is been processed as HTML instead of JSON. An second it is not sent to Angular back.
I got it working!
I configure my Rails api to accept cross-domain request by putting this configuration in config/application.rb
config.action_dispatch.default_headers = {
'Access-Control-Allow-Origin' => '*',
'Access-Control-Request-Method' => '*'
}
my service file with the resource call:
factory('Boat', function($resource){
return $resource('http://127.0.0.1\\:3000/:boatId', {}, {
query: {method:'GET', params:{boatId:'boats'}, isArray:true}
});
}).
and my Rails API controller:
def index
#boats = Boat.all
puts #boats
render :json => #boats
end
It looks easy, but this combination took me three days.

Resources