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

Popular posts

FastReport Designer Community Edition

How to use FastReport Open Source in ASP.NET Core Web API application