我怎样才能保持我的Angular 2应用程序的进展状态的对话框? [英] How can I maintain the state of dialog box with progress all over my Angular 2 application?
问题描述
我想保持Md对话框的状态,即使我关闭了对话框,这样我可以保持上传状态在整个应用程序中处于活动状态。我的计划是将上传响应存储在服务中以保持上传进度,并在工具栏中给出一个图标。每次对话框都会重新初始化。我怎样才能保持对话框的状态与上传进度遍及应用程序?
app.component.ts
从'@ angular / core'导入{Component,NgZone,Inject,EventEmitter};
从'ngx-uploader'导入{NgUploaderOptions,UploadedFile,UploadRejected};
从'@ angular / material'导入{MdDialog,MdDialogRef,MdDialogConfig};
从'@ angular / router'导入{Router};
从'./upload.service'导入{UploadService};
导入'./operators';
$ b @Component({
moduleId:module.id,
selector:'sd-app',
templateUrl:'app.component.html',
})
导出类AppComponent {
temp:any;
dialogRef:MdDialogRef< DialogComponent>;
config:MdDialogConfig = {
disableClose:true
};
构造函数(公共对话:MdDialog,私有路由器:路由器,公共uploadService:UploadService){
this.temp = this.uploadService.getUpload();
openDialog(){
this.dialogRef = this.dialog.open(DialogComponent,this.config);
}
}
app.component .html
< md-progress-bar mode =determinate
[value] =temp.progress .percent
color =primary
class =progress-bar-margins>
< / md-progress-bar>
< span> {{temp.progress.percent}}%< / span>
对话元件
导出类DialogComponent {
选项:NgUploaderOptions;
回应:任何;
sizeLimit:number = 1024 * 1024 * 50; // 50MB
previewData:any;
errorMessage:string;
inputUploadEvents:EventEmitter< string>;
temp:any;
构造函数(@Inject(NgZone)private zone:NgZone,public uploadService:UploadService){
this.options = new NgUploaderOptions({$ b $ url:'http:// api 。'x'uploader.com / upload',
filterExtensions:false,
allowedExtensions:['dsn'],
data:{userId:12},$ b $ autoUpload:false,
fieldName:'file',
fieldReset:true,
maxUploads:2,
方法:'POST',
previewUrl:true,
withCredentials:假
});
this.inputUploadEvents = new EventEmitter< string>();
}
startUpload(view:any){
this.inputUploadEvents.emit('startUpload');
beforeUpload(uploadingFile:UploadedFile):void {
if(uploadingFile.size> this.sizeLimit){
console.log('File is too large!') ;
this.errorMessage ='文件太大!请选择有效的文件';
uploadingFile.setAbort();
handleUpload(data:any){
setTimeout(()=> {
this.zone.run(()= > {
this.response = data;
this.uploadService.uploadData = data;
this.temp = this.uploadService.getUpload();
if(data& & data.response){
this.response = JSON.parse(data.response);
}
});
});
}
handlePreviewData(data:any){
this.previewData = data;
$ / code $ / pre
$ b $ h3 upload.component.html / $ 3
< button type =buttonclass =start-upload-button(click)=startUpload()>开始上传<按钮>
< / div>
< < div * ngIf =previewData&&!response>
< img [src] =previewData>
< / div>
< div>
[value] =temp.progress.percent
color =primary
class =progress-bar -margins>
< / md-progress-bar>
< span> {{temp.progress.percent}}%< / span>
< / div>
upload.service.ts
<$ p $从'@ angular / core'导入{@ c $ c> import {Injectable};
从'rxjs / Rx'导入{BehaviorSubject};
从'rxjs'导入{Observable};
从'rxjs / Rx'导入{主题};
@Injectable()
导出类UploadService {
uploadData:any;
构造函数(){
console.log('Global Service initialised');
}
getUpload(){
return this.uploadData;
$ / code $ / pre
解决方案用于构建UI界面的流量架构模式:
即使在那里是由UI触发的动作:
import { Component, NgZone, Inject, EventEmitter } from '@angular/core';
import { NgUploaderOptions, UploadedFile, UploadRejected } from 'ngx-uploader';
import { MdDialog, MdDialogRef, MdDialogConfig } from '@angular/material';
import { Router } from '@angular/router';
import { UploadService } from './upload.service';
import './operators';
@Component({
moduleId: module.id,
selector: 'sd-app',
templateUrl: 'app.component.html',
})
export class AppComponent {
temp:any;
dialogRef: MdDialogRef<DialogComponent>;
config: MdDialogConfig = {
disableClose: true
};
constructor(public dialog: MdDialog, private router: Router, public uploadService: UploadService ) {
this.temp = this.uploadService.getUpload();
}
openDialog() {
this.dialogRef = this.dialog.open(DialogComponent, this.config);
}
}
app.component.html
<md-progress-bar mode="determinate"
[value]="temp.progress.percent"
color="primary"
class="progress-bar-margins">
</md-progress-bar>
<span>{{temp.progress.percent}}%</span>
Dialog Component
export class DialogComponent {
options: NgUploaderOptions;
response: any;
sizeLimit: number = 1024 * 1024 * 50; // 50MB
previewData: any;
errorMessage: string;
inputUploadEvents: EventEmitter<string>;
temp:any;
constructor(@Inject(NgZone) private zone: NgZone, public uploadService: UploadService) {
this.options = new NgUploaderOptions({
url: 'http://api.ngx-uploader.com/upload',
filterExtensions: false,
allowedExtensions: ['dsn'],
data: { userId: 12 },
autoUpload: false,
fieldName: 'file',
fieldReset: true,
maxUploads: 2,
method: 'POST',
previewUrl: true,
withCredentials: false
});
this.inputUploadEvents = new EventEmitter<string>();
}
startUpload(view:any) {
this.inputUploadEvents.emit('startUpload');
}
beforeUpload(uploadingFile: UploadedFile): void {
if (uploadingFile.size > this.sizeLimit) {
console.log('File is too large!');
this.errorMessage = 'File is too large! Please select valid file';
uploadingFile.setAbort();
}
}
handleUpload(data: any) {
setTimeout(() => {
this.zone.run(() => {
this.response = data;
this.uploadService.uploadData = data;
this.temp = this.uploadService.getUpload();
if (data && data.response) {
this.response = JSON.parse(data.response);
}
});
});
}
handlePreviewData(data: any) {
this.previewData = data;
}
}
upload.component.html
<button type="button" class="start-upload-button" (click)="startUpload()">Start Upload</button>
</div>
< <div *ngIf="previewData && !response">
<img [src]="previewData">
</div>
<div>
<md-progress-bar mode="determinate"
[value]="temp.progress.percent"
color="primary"
class="progress-bar-margins">
</md-progress-bar>
<span>{{temp.progress.percent}}%</span>
</div>
upload.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/Rx';
import { Observable } from 'rxjs';
import { Subject } from 'rxjs/Rx';
@Injectable()
export class UploadService {
uploadData :any;
constructor() {
console.log('Global Service initialised');
}
getUpload() {
return this.uploadData;
}
}
解决方案 Use the flux architectural pattern for building UI interfaces:
https://facebook.github.io/flux/ (just read about it, don't actually use the facebook API).
It turns out that the pattern is very useful for maintaining application state across multiple components - especially for large scale applications.
The idea is simple - in a flux architecture, data always flows in one direction:
This is true, even when there is an action triggered from the UI:
In your Angular2 application, the dispatcher are your Observables implemented on your service (any component that injects the service can subscribe to it) and the store is a cached copy of the data to aid in emitting events.
Here is an example of a ToDoService that implements the Flux architecture:
import { Injectable } from '@angular/core';
import {Http } from '@angular/http';
import { BehaviorSubject, Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/toPromise';
export interface ToDo {
id: number;
name:string;
isComplete: boolean;
date: Date;
}
@Injectable()
export class ToDoService {
public todoList$:Observable<ToDo[]>;
private subject: BehaviorSubject<ToDo[]>;
private store: {
todos: ToDo[];
}
public constructor(private http:Http) {
this.subject = new BehaviorSubject<ToDo[]>([]);
this.todoList$ = this.subject.asObservable();
this.store = {
todos: []
};
}
public remove(todo:ToDo) {
this.http.delete(`http://localhost/todoservice/api/todo/${todo.id}`)
.subscribe(t=> {
this.store.todos.forEach((t, i) => {
if (t.id === todo.id) { this.store.todos.splice(i, 1); }
});
let copy = this.copy(this.store).todos;
this.subject.next(copy);
});
}
public update(todo:ToDo): Promise<ToDo> {
let q = this.http.put(`http://localhost/todoservice/api/todo/${todo.id}`, todo)
.map(t=>t.json()).toPromise();
q.then(x=> {
this.store.todos.forEach((t,i) => {
if (t.id == x.id) { Object.assign(t, x); }
let copy = this.copy(this.store).todos;
this.subject.next(copy);
});
});
return q;
}
public getAll() {
this.http.get('http://localhost/todoservice/api/todo/all')
.map(t=>t.json())
.subscribe(t=> {
this.store.todos = t;
let copy = Object.assign({}, this.store).todos;
this.subject.next(copy);
});
}
private copy<T>(t:T):T {
return Object.assign({}, t);
}
}
There are several things to notice about this service:
- The service stores a cached copy of the data store
{ todos: ToDo[] }
- It exposes an Observable that components can subscribe to (if they are interested)
- It uses a BehaviourSubject which is private to its implementation. A BehaviorSubject will emit an initial value when subscribed to. This is handy if you want to initialize the Observable with an empty array to begin with.
- Whenever a method is called that mutates the data store (remove or update), the service makes a web service call to update its persistent store, it then updates its cached data store before emitting the updated
ToDo[]
list to all of its subscribers
- A copy of the data is emitted from the service to prevent unexpected data changes from propagating in the opposite direction (this is important for maintaining the flux pattern).
Any component that DI injects the Service has an opportunity to subscribe to the todoList$
observable.
In the following component, we take advantage of the async pipe instead of subscribing to the todoList$
observable directly:
Component.ts
ngOnInit() {
this.todoList$ = this.todoService.todoList$;
}
Component.html
<li class="list-group-item" *ngFor="let item of todoList$ | async">
{{ item.name }}
</li>
Whenever a method is called on the service that modifies its internal store, the service updates all of its component subscribers, regardless of which component initiated the change.
The Flux pattern is an excellent pattern for managing complex UIs and reducing the coupling between components. Instead, the coupling is between the Service and the Component, and the interaction is mainly for the component to subscribe to the service.
这篇关于我怎样才能保持我的Angular 2应用程序的进展状态的对话框?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!