How to use WebReport in Single Page Application Angular 7
If you use
FastReport.Net in your ASP.Net Core applications and want to switch to a
single-page application (SPA), then this article is for you. Thanks to the
symbiosis of Angular and ASP.Net Core, you can use your familiar MVC
application architecture.
Let's take
a look at the way to create a SPA application. This will be useful for those
who are just going to learn Angular. To work with Angular, you need to install
Node.js, a platform for executing JavaScript code on the server side. The
easiest way is to download the installer from the developer’s website
https://nodejs.org/en/. It also requires .Net Core SDK 2.0 or newer versions.
If you have Microsoft Visual Studio 2017 installed, then the SDK is already
installed.
Now we create a folder
for our future application in the desired place. Run the command prompt. Go to
the created directory using the cd command. And we execute the command:
dotnet new angular -o SPAWebReport
This
command will create a three-page demo application.
Open the
created project. First, we will need to install additional packages in the
NuGet manager:
The
FastReport.Core and FastReport.Web packages can be found in the NuGet folder in
the FastReport.Net installation directory. To install these packages, you need
to set up a local package repository. In the upper right corner of the package
manager there is a drop-down list for selecting the source of packages and the
gear icon. By clicking on this icon, you will see the settings window, where
for the local source you will specify the path to the NuGet folder.
We need a
report and a database for it. Add the App_Data folder to the project root and
drag the Master-Detail.frx and nwind.xml files into it. These files can be found
in the FastReport.Net installation directory in the Demos -> Reports folder.
At the root
of the project is the Controllers directory, which already contains one
controller. We use it. Add just one method:
using FastReport.Web;
…
[HttpGet("[action]")]
public IActionResult ShowReport()
{
WebReport WebReport = new WebReport();
WebReport.Width = "1000";
WebReport.Height = "1000";
WebReport.Report.Load("App_Data/Master-Detail.frx"); // Load the report into the WebReport object
System.Data.DataSet dataSet = new System.Data.DataSet(); // Create a data source
dataSet.ReadXml("App_Data/nwind.xml"); // Open the xml database
WebReport.Report.RegisterData(dataSet, "NorthWind"); // Registering the data source in the report
ViewBag.WebReport = WebReport; // pass the
report to View
return View();
}
Now you
need to create a view for it. Add the Views folder to the project root. And in
it one more SampleData. Now in this folder we will create the ShowReport.cshtml
view with this code:
@await ViewBag.WebReport.Render()
In our demo
SPA there are three unnecessary web pages. You can safely delete these pages;
we are only interested in app.component.htm - this is the page template. For
this template, there is a corresponding script app.component.ts. Here we are to
work with him mainly.
You can set
the page template in the app.component.htm file, or you can set it directly in
the script, in the template parameter of the component.
Our task is
to “cross” angular and ASP .Net Core. This means that we will use the
controller and views for action. Quite a standard ASP .Net Core MVC
application. The easiest solution is to pass a view in the iframe:
App.component.ts:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `<div>
<iframe id="report" height="1000"
width="1000" src=
"api/SampleData/ShowReport"></iframe>
</div>`
})
export class AppComponent {
}
Such a simple code allows you to display the
report immediately when loading the SPA application. This is suitable if you
have selected a separate page for the report, but if you need more
interactivity? For example, a button that, when clicked, loads the report.
Let's add a button to the page template, as well as a button click event and
its handler:
@Component({
selector: 'app-root',
template: `<div>
<input
type="button" (click)="Clicked()" value = "Show
Report"/>
<div
*ngIf="show">
<iframe
id="report" height="1000" width="1000" src=
"api/SampleData/ShowReport"></iframe>
</div>
</div>`
})
export class AppComponent {
show: boolean = false;
Clicked() {
this.show = true;
}
}
We added a
button and a clicked event in its attributes. But how to hide the frame before
the button is pressed? To do so, we wrapped the frame in a div that has a
condition - check the ‘show’ variable for ‘true’. By default, this variable is
set to false, so this div will not be shown when the page is displayed. Thus,
the Clicked function simply sets the value of the show variable to true.
It would be
good to put the src value for the frame into a variable and set it in the
clicked function. However,
if you just do this:
…
<iframe id="report" height="1000"
width="1000" [src]="url | safeUrl"></iframe>
…
url: string;
Clicked() {
this.show = true;
this.url = "api/SampleData/ShowReport";
}
That will not work. The fact is that the link
needs to be normalized using a special “cleaner” - DOMSanitizer. It is designed
to make html code and url safe from malicious inclusions.
Let's create the safeUrl.pipe.ts script in the
app folder:
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Pipe({ name: 'safeUrl' })
export class SafeUrlPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) { }
transform(url) {
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
}
}
This class will check the url for security in
the correct format. In order to use this Pipe in the app.component, we need to
add it to the modules in app.module.ts:
…
import { SafeUrlPipe } from "./safeUrl.pipe";
@NgModule({
declarations: [
AppComponent,
SafeUrlPipe
],
imports: [
BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Let's go
back to app.component.ts. Now we can use Pipe:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `<div>
<input
type="button" (click)="Clicked()" value = "Show
Report"/>
<div
*ngIf="show">
<iframe id="report"
height="1000" width="1000" [src]="url |
safeUrl"></iframe>
</div>
</div>`
})
export class AppComponent {
show: boolean = false;
url: string;
Clicked() {
this.show = true;
this.url = "api/SampleData/ShowReport";
}
}
Further developing the idea, you can add the
parameter name of the report to the ShowReport method, and get the desired
report at the output.
There is a final touch before launching the
application. Open the Startup.cs file and add one line to the Configure ()
method:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
…
app.UseFastReport();
…
}
Thus, we connected to the application
FastReportBuilderExtensions, which will allow rendering reports.
And now let's run our demo application:
By pressing
the button, we got the desired report. As you can see, there is nothing
difficult to use FastReport with Angular SPA. If, in addition to reports, you
want to use an online designer, then pay attention to another article - How to use Online Designer in a Single Page
Application Angular 7.
Comments
Post a Comment