Previewing files using a service

One of the challenges of developing UI applications is that there is a tendency for logic to creep into views that does not belong there. It becomes convenient to put a piece of logic in our ts views file because we know that the view is going to call out to it, but it does something that does not have any visible impact on the client.

We might, for instance, want to write some values from the UI back to the server. The only part of this that is relevant to the view is the data part; the actual writing to the server is a completely different responsibility. It would be useful to us if we had a simple way to create external classes that we could inject wherever we needed so that we would not need to worry about how to instantiate them. They would just be available to us to use whenever we needed them. Fortunately for us, the authors of Angular saw that there would be a need for this and provided us with services.

A service is simply a class that uses the @Injectable decorator and has an entry in the declarations section of the module. Apart from those requirements, there's nothing else that is needed, so we could easily handcraft the class if we needed to. While we could do this, there's no real reason to, because Angular helps us to generate the service using the following command:

ng generate service <<servicename>>

When we create the service, we don't actually have to add service at the end of the name as this command automatically does that for us. To see how this works, we are going to create a service that takes a file that has been chosen using the file selector and then reads it in so that it can be displayed back in the image upload dialog and on the main screen, or transferred over to be saved in the database. We start with the following command:

ng generate service Services/FilePreviewService.
I like to generate my services in a Services sub-folder. Putting this in the filename creates it in the Services folder.

The ng generate service command gives us the following basic outline:

import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class FilePreviewService {
}

Reading a file can be a time-consuming process, so we know that we want this operation to happen asynchronously. As we discussed in earlier chapters, we could do this with a callback, but a much better method is to use a promise. We add the following method call to the service:

public async Preview(files: any): Promise<IPictureModel> {
}

As this is the point at which we are going to read the file in, this is when we are going to create the model that we are going to use to pass the data around our application. The model that we are going to use looks like this:

export interface IPictureModel {
Image: string;
Name: string;
Description: string;
Tags: string;
}
export class PictureModel implements IPictureModel {
Image: string;
Name: string;
Description: string;
Tags: string;
}

Image holds the actual image that we are going to read in, and Name is the name of the file. This is why we populate this model at this point; we are working with the file itself so this is the point at which we have the filename available to us. The Description and Tags strings will be added by the image upload component. While we could create an intersection type at that point, for a simple model like this, it is enough to have a single model hold them.

The fact that we have said that we are using Promise means that we need to return an appropriate Promise from our Preview method:

return await new Promise((resolve, reject) => {});

Inside the Promise, we are going to create an instance of our model. As it is good practice, we are going to add some defensive code to ensure that we have an image file. If the file is not an image file, we are going to reject it, which can be handled gracefully by the calling code:

if (files.length === 0) {
return;
}
const file = files[0];
if (file.type.match(/image/*/) === null) {
reject(`The file is not an image file.`);
return;
}
const imageModel: IPictureModel = new PictureModel();

When we reach this point, we know that we have a valid file, so we are going to set the name in the model using the filename, as well as using FileReader to read the image using readAsDataURL. When the read finishes, the onload event is raised, allowing us to add the image data to our model. At this point, we can resolve our promise:

const reader = new FileReader();
reader.onload = (evt) => {
imageModel.Image = reader.result;
resolve(imageModel);
};
reader.readAsDataURL(file);
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.183.89