博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
hapi_带有节点和Hapi后端的Angular文件上传
阅读量:2512 次
发布时间:2019-05-11

本文共 13601 字,大约阅读时间需要 45 分钟。

hapi

In this article, we will talk about how to handle file uploads with Angular. We will create an images uploader that allow user to upload single or multiple images file by drag and drop or select file dialog.

在本文中,我们将讨论如何使用Angular处理文件上传。 我们将创建一个图像上传器,允许用户通过拖放或选择文件对话框上传单个或多个图像文件。

We will then upload the selected images and display them accordingly. We will also learn to filter the upload file type, for example, we only allow images, do not allow file type like PDF.

然后,我们将上传选定的图像并进行相应显示。 我们还将学习过滤上传文件的类型,例如,我们只允许图片,不允许像PDF这样的文件类型。

Image uploader

  • Sourcecode:

    源代码: :
  • Demo:

    演示: :

( )

File upload consists of two parts: the UI (front-end) and the API (back-end). We will be using Angular to handle the UI part. We need a backend application to accept the uploaded files. You may follow the backend tutorials or download and run either one of these server side application to handle file upload for your backend:-

文件上传由两部分组成: UI(前端)API(后端) 。 我们将使用Angular处理UI部分。 我们需要一个后端应用程序来接受上传的文件。 您可以按照后端教程进行操作,也可以下载并运行以下任一服务器端应用程序来处理后端的文件上传:-

  • File upload with Hapi.js: , or

    使用Hapi.js上传文件: ://scotch.io/bar-talk/handling-file-uploads-with-hapi-js,或者
  • File upload with Express + Multer: , or

    使用Express + Multer上传文件: ://scotch.io/tutorials/express-file-uploads-with-multer,或者
  • Switch to any cloud solution of your choice (Amazon S3, Google Drive, etc).

    切换到您选择的任何云解决方案(Amazon S3,Google Drive等)。

We will be using File upload with Hapi.js as our backend throughout this articles. We will also learn the tricks to enable fake upload on the front-end.

在本文中,我们将使用Hapi.js的文件上传作为我们的后端。 我们还将学习在前端启用假冒上传的技巧。

( )

Alright, let's start creating our Angular file upload component.

好了,让我们开始创建Angular文件上传组件。

Upload images

Drag your file(s) here to begin

or click to browse

Uploading {

{ photos.files.length }} files...

Notes:-

笔记:-

  1. Our upload form will have a few statuses: STATUS_INITIAL, STATUS_SAVING, STATUS_SUCCESS, STATUS_FAILED, the variable name is pretty expressive themselves.

    我们的上传表单将具有以下几种状态:STATUS_INITIAL,STATUS_SAVING,STATUS_SUCCESS,STATUS_FAILED,变量名本身具有很强的表现力。
  2. We will display the upload form when the status is initial or saving.

    状态为初始或保存时,我们将显示上传表单。
  3. The form attribute enctype="multipart/form-data" is important. To enable file upload, this attribute must be set. Learn more about enctype .

    表单属性enctype="multipart/form-data"很重要。 要启用文件上传,必须设置此属性。 了解有关enctype的更多信息。
  4. We have a file input <input type="file" /> to accept file upload. The property multiple indicate it's allow multiple file upload. Remove it for single file upload.

    我们有一个文件输入<input type="file" />来接受文件上传。 属性multiple表示允许上传多个文件。 将其删除以上传单个文件。
  5. We will handle the file input change event. Whenever the file input change (someone drop or select files), we will trigger the filesChange function and pass in the control name and selected files $event.target.files, and then upload to server.

    我们将处理文件输入change事件。 每当文件输入更改(有人删除或选择文件)时,我们将触发filesChange函数并传入控件名称和所选文件$event.target.files ,然后上载到服务器。
  6. We limit the file input to accept images only with the attribute accept="image/*".

    我们将文件输入限制为仅接受具有属性accept="image/*"
  7. The file input will be disabled during upload, so user can only drop / select files again after upload complete.

    上传过程中将禁用文件输入,因此用户只能在上传完成后再次删除/选择文件。
  8. We set a template variable #photos to the file input. This gives us a reference to the file input control. Later, you can see we use the photos variable in displaying number of files uploading Uploading {
    { photos.files.length }} files...
    .

    我们将模板变量#photos设置为文件输入。 这为我们提供了文件输入控件的参考。 稍后,您可以看到我们使用photos变量显示了上传的文件数。 Uploading {
    { photos.files.length }} files...

( )

Now, that's the interesting part. Currently, our component look like this:

现在,这是有趣的部分。 当前,我们的组件如下所示:

File upload component without styling

We need to transform it to look like this:

我们需要将其转换为如下形式:

File upload component with styling

Let's style it!

让我们来造型​​吧!

/* page-file-upload.component.css */.dropbox {
outline: 2px dashed grey; /* the dash box */ outline-offset: -10px; background: lightcyan; color: dimgray; padding: 10px 10px; min-height: 200px; /* minimum height */ position: relative; cursor: pointer;}.dropbox:hover {
background: lightblue; /* when mouse over to the drop zone, change color */}input[type="file"] {
opacity: 0; /* invisible but it's there! */ width: 100%; height: 200px; position: absolute; cursor: pointer;}.dropbox p {
font-size: 1.2em; text-align: center; padding: 50px 0;}

With only few lines of css, our component looks prettier now.

只需几行CSS,我们的组件现在看起来更漂亮了。

Notes:-

笔记:-

  1. We make the file input invisible by applying opacity: 0 style. This doesn't hide the file input, it just make it invisible.

    我们通过应用opacity: 0样式使文件输入不可见。 这不会隐藏文件输入,只会使其不可见。
  2. Then, we style the file input parent element, the dropbox css class. We make it look like a drop file zone surround with dash.

    然后,我们设置文件输入父元素dropbox css类的样式。 我们使它看起来像是一个带有短划线的拖放文件区域。
  3. Then, we align the text inside dropbox to center.

    然后,我们将Dropbox中的文本对齐到中心。

( )

Let's proceed to code our component class.

让我们继续编写我们的组件类。

// page-file-upload.component.tsimport {
Component } from '@angular/core';import {
FileUploadService } from './file-upload.service'; // we will create this next!@Component({
selector: 'page-file-upload', templateUrl: './page-file-upload.component.html', styleUrls: ['./page-file-upload.component.css']})export class PageFileUploadComponent {
uploadedFiles = []; uploadError; currentStatus: number; uploadFieldName = 'photos'; readonly STATUS_INITIAL = 0; readonly STATUS_SAVING = 1; readonly STATUS_SUCCESS = 2; readonly STATUS_FAILED = 3; constructor(private _svc: FileUploadService) {
this.reset(); // set initial state } filesChange(fieldName: string, fileList: FileList) {
// handle file changes const formData = new FormData(); if (!fileList.length) return; // append the files to FormData Array .from(Array(fileList.length).keys()) .map(x => {
formData.append(fieldName, fileList[x], fileList[x].name); }); // save it this.save(formData); } reset() {
this.currentStatus = this.STATUS_INITIAL; this.uploadedFiles = []; this.uploadError = null; } save(formData: FormData) {
// upload data to the server this.currentStatus = this.STATUS_SAVING; this._svc.upload(formData) .take(1) .delay(1500) // DEV ONLY: delay 1.5s to see the changes .subscribe(x => {
this.uploadedFiles = [].concat(x); this.currentStatus = this.STATUS_SUCCESS; }, err => {
this.uploadError = err; this.currentStatus = this.STATUS_FAILED; }) }}

Notes:-

笔记:-

  1. Later on, we will call the API to upload images, the API accept a field call photos. That's our file input field name.

    稍后,我们将调用 API来上传图片,该API接受现场调用photos 。 那就是我们的文件输入字段名称。
  2. We handle the file changes with the filesChange function. FileList is an object returned by the files property of the HTML element. It allow us to access the list of files selected with the element. Learn more [here](().

    我们使用filesChange函数处理文件更改。 FileList是HTML元素的files属性返回的对象。 它允许我们访问用元素选择的文件的列表。 在此处[( )了解更多信息。
  3. We then create a new FormData, and append all our photos files to it. FormData interface provides a way to easily construct a set of key/value pairs representing form fields and their values. Learn more .

    然后,我们创建一个新的FormData ,并将所有photos文件附加到该文件。 FormData接口提供了一种轻松构造一组代表表单字段及其值的键/值对的方法。 了解更多。
  4. The save function will call our file upload service (hang on, we will create the service next!). We also set the status according to the result.

    save功能将调用我们的文件上传服务(继续,我们接下来将创建该服务!)。 我们还根据结果设置状态。

( )

// file-upload.service.tsimport {
Injectable } from '@angular/core';import {
Http, RequestOptionsArgs, Headers } from '@angular/http';@Injectable()export class FileUploadService {
baseUrl = 'http://localhost:3001'; // our local Hapi Js API constructor(private _http: Http) {
} upload(formData) {
const url = `${
this.baseUrl}/photos/upload`; return this._http.post(url, formData) .map(x => x.json()) .map((x: any[]) => x // add a new field url to be used in UI later .map(item => Object .assign({
}, item, {
url: `${
this.baseUrl}/images/${
item.id}` })) ); }}

Nothing much, the code is pretty expressive itself. We upload the files, wait for the result, map it accordingly.

没什么,代码本身也很容易表达。 我们上传文件,等待结果,并相应地映射它。

Now wire up your component and service to module, usually app.module.ts, and run it.

现在,将您的组件和服务连接到模块(通常是app.module.ts )并运行它。

( )

We can upload the files successfully now. However, there's no indication in UI. Let's update our HTML.

我们现在可以成功上传文件。 但是,UI中没有指示。 让我们更新我们HTML。

...

Uploaded {
{ uploadedFiles.length }} file(s) successfully.

Upload again

Uploaded failed.

Try again

{
{ uploadError | json }}

Notes:-

笔记:-

  1. Display the uploaded image when upload successfully.

    成功上传后显示上传的图像。
  2. Display the error message when upload failed.

    上载失败时显示错误消息。

( )

If you are lazy to start the back-end application (Hapi, Express, etc) to handle file upload. Here is a fake service to replace the file upload service.

如果您懒于启动后端应用程序(Hapi,Express等)来处理文件上传。 这是一项伪造的服务,用来代替文件上传服务。

// file-upload.fake.service.tsimport {
Injectable } from '@angular/core';import {
Observable } from 'rxjs/Rx';@Injectable()export class FileUploadFakeService {
upload(formData: any) {
const photos: any[] = formData.getAll('photos'); const promises = photos.map((x: File) => this.getImage(x) .then(img => ({
id: img, originalName: x.name, fileName: x.name, url: img }))); return Observable.fromPromise(Promise.all(promises)); } private getImage(file: File) {
return new Promise((resolve, reject) => {
const fReader = new FileReader(); const img = document.createElement('img'); fReader.onload = () => {
img.src = fReader.result; resolve(this.getBase64Image(img)); } fReader.readAsDataURL(file); }) } private getBase64Image(img) {
const canvas = document.createElement('canvas'); canvas.width = img.width; canvas.height = img.height; const ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0); const dataURL = canvas.toDataURL('image/png'); return dataURL; }}

Came across this solution in this . Pretty useful. My online is using this service.

在此此解决方案。 很有用。 我的在线正在使用此服务。

Basically, what the code do is read the source, draw it in canvas, and save it as data url with the canvas toDataURL function. Learn more about canvas .

基本上,代码要做的是读取源代码,将其绘制在画布中,然后使用canvas toDataURL函数将其另存为数据url。 了解有关画布的更多信息。

If you realize, our fake service has a same public interface as the real file upload service, both has upload function and return list of files. This is important for the next step, swap the real file upload service with the fake one.

如果您意识到,我们的虚假服务具​​有与真实文件上传服务相同的公共接口,既具有upload功能,又具有文件返回列表。 这对下一步很重要,将真实文件上传服务与伪造文件交换服务交换。

( )

First you might think that to use the fake service, you need to register the fake service in module, and import it in our file upload component like how we do usually. However, there's a quicker way, with Angular dependency injection (DI). Let's look at our App module.

首先,您可能会认为要使用伪造的服务,您需要在模块中注册伪造的服务,然后像通常一样将其导入到我们的文件上传组件中。 但是,有了Angular依赖注入(DI),有一种更快的方法。 让我们看看我们的App模块。

// app.module.ts...import {
PageFileUploadComponent, FileUploadFakeService, FileUploadService } from './file-upload';@NgModule({
... providers: [ // FileUploadService, // normally we do this, comment it, we do the below instead {
provide: FileUploadService, useClass: FileUploadFakeService }, // we can do this instead ], ...})export class AppModule {
}

With this, you don't need to change your component code, stop your backend API, refresh the browser, you should see our app is still working, calling fake service instead.

这样,您无需更改组件代码,停止后端API,刷新浏览器,您应该会看到我们的应用程序仍在运行,而改为调用伪造服务。

In short, Providers: [FileUploadService] is the short form of Providers: [{ provide: FileUploadService, useClass: FileUploadService }]. Therefore, as long as we have another class with similar interface, we can swap it easily.

简而言之, Providers: [FileUploadService]Providers: [{ provide: FileUploadService, useClass: FileUploadService }]的简称Providers: [{ provide: FileUploadService, useClass: FileUploadService }] 。 因此,只要我们有另一个具有相似接口的类,我们就可以轻松地对其进行交换。

Angular DI is powerful. We'll leave that for another post.

Angular DI功能强大。 我们将其留在另一篇文章中。

( )

That's it. This is how you can handle file upload without using any 3rd party libraries and plugins in Angular. It isn't that hard right?

而已。 这是您无需使用Angular中的任何第三方库和插件即可处理文件上传的方式。 这不是很难吗?

Happy coding!

编码愉快!

The UI (Front-end)

用户界面(前端)

  • Sourcecode:

    源代码: :
  • Demo:

    演示: :

The API (Back-end)

API(后端)

  • File upload with Hapi.js: , or

    使用Hapi.js上传文件: ://scotch.io/bar-talk/handling-file-uploads-with-hapi-js,或者
  • File upload with Express + Multer: , or

    使用Express + Multer上传文件: ://scotch.io/tutorials/express-file-uploads-with-multer,或者
  • Switch to any cloud solution of your choice (Amazon S3, Google Drive, etc).

    切换到您选择的任何云解决方案(Amazon S3,Google Drive等)。

翻译自:

hapi

转载地址:http://ueuwd.baihongyu.com/

你可能感兴趣的文章
Powershell-远程操作
查看>>
Java基础学习笔记二十一 多线程
查看>>
使用Java Low Level REST Client操作elasticsearch
查看>>
css3 抖动
查看>>
移动端手势
查看>>
[Linked List]Insertion Sort List
查看>>
Product of Array Except Self
查看>>
[Tree]Binary Tree Inorder Traversal
查看>>
Response.Redirect和Server.Transfer比较
查看>>
European software vendors ranking 2012 (zz)
查看>>
甘油三酯 (zz)
查看>>
Publish的时候某些需要用到的文件没deploy上去
查看>>
五班二组白盒测试实践进度(4)
查看>>
html/css基础篇——关于浏览器window、document、html、body高度的探究
查看>>
tomcat部署项目的三种方式
查看>>
POJ 2015 Permutation Code
查看>>
BZOJ3153 : Sone1
查看>>
[Shell]做一个自己的rm命令来替换系统自带的,以免误删除之后恢复不了
查看>>
记一次服务器被植入挖矿木马cpu飙升200%解决过程
查看>>
jq实现全选、全不选、反选
查看>>