如何在整个 Angular 2 应用程序中保持对话框的状态和进度?
How can I maintain the state of dialog box with progress all over my Angular 2 application?
我想保持 Md 对话框的状态,即使我关闭 dialog.So 我可以保持整个应用程序的上传状态处于活动状态。我的计划是将上传响应存储在服务中以保持上传进度,并且每次都会在 toolbar.The 对话框中给出一个图标重新初始化。如何在整个应用程序中维护对话框的状态以及上传进度?
app.component.ts
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>
对话框组件
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;
}
}
使用 flux 架构模式构建 UI 接口:
https://facebook.github.io/flux/(只是看看而已,不要真的用脸书API)。
事实证明,该模式对于跨多个组件维护应用程序状态非常有用 - 特别是对于大型应用程序。
这个想法很简单——在通量架构中,数据总是在一个方向上流动:
这是真的,即使 UI:
触发了一个动作
在您的 Angular2 应用程序中,调度程序是在您的服务上实现的 Observables(任何注入该服务的组件都可以订阅它),而存储是数据的缓存副本以帮助发出事件。
下面是一个实现 Flux 架构的 ToDoService 示例:
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);
}
}
关于此服务有几点需要注意:
- 服务存储数据存储的缓存副本
{ todos: ToDo[] }
- 它公开了一个组件可以订阅的 Observable(如果他们感兴趣的话)
- 它使用对其实现私有的 BehaviourSubject。 BehaviorSubject 在订阅时会发出一个初始值。如果你想用一个空数组开始初始化 Observable,这会很方便。
- 每当调用改变数据存储(删除或更新)的方法时,服务都会调用 Web 服务来更新其持久存储,然后在发出更新后的
ToDo[]
之前更新其缓存的数据存储列出其所有订阅者
- A copy 数据从服务中发出,以防止意外的数据更改向相反方向传播(这很重要用于维持通量模式)。
DI 注入服务的任何组件都有机会订阅 todoList$
可观察对象。
在以下组件中,我们利用异步管道而不是直接订阅 todoList$
可观察对象:
Component.ts
ngOnInit() {
this.todoList$ = this.todoService.todoList$;
}
Component.html
<li class="list-group-item" *ngFor="let item of todoList$ | async">
{{ item.name }}
</li>
每当在服务上调用修改其内部存储的方法时,服务都会更新其所有组件订阅者,而不管哪个组件发起了更改。
Flux 模式是管理复杂 UI 和减少组件之间耦合的优秀模式。而是耦合在Service和Component之间,交互主要是组件订阅服务
我想保持 Md 对话框的状态,即使我关闭 dialog.So 我可以保持整个应用程序的上传状态处于活动状态。我的计划是将上传响应存储在服务中以保持上传进度,并且每次都会在 toolbar.The 对话框中给出一个图标重新初始化。如何在整个应用程序中维护对话框的状态以及上传进度?
app.component.ts
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>
对话框组件
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;
}
}
使用 flux 架构模式构建 UI 接口:
https://facebook.github.io/flux/(只是看看而已,不要真的用脸书API)。
事实证明,该模式对于跨多个组件维护应用程序状态非常有用 - 特别是对于大型应用程序。
这个想法很简单——在通量架构中,数据总是在一个方向上流动:
这是真的,即使 UI:
触发了一个动作在您的 Angular2 应用程序中,调度程序是在您的服务上实现的 Observables(任何注入该服务的组件都可以订阅它),而存储是数据的缓存副本以帮助发出事件。
下面是一个实现 Flux 架构的 ToDoService 示例:
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);
}
}
关于此服务有几点需要注意:
- 服务存储数据存储的缓存副本
{ todos: ToDo[] }
- 它公开了一个组件可以订阅的 Observable(如果他们感兴趣的话)
- 它使用对其实现私有的 BehaviourSubject。 BehaviorSubject 在订阅时会发出一个初始值。如果你想用一个空数组开始初始化 Observable,这会很方便。
- 每当调用改变数据存储(删除或更新)的方法时,服务都会调用 Web 服务来更新其持久存储,然后在发出更新后的
ToDo[]
之前更新其缓存的数据存储列出其所有订阅者 - A copy 数据从服务中发出,以防止意外的数据更改向相反方向传播(这很重要用于维持通量模式)。
DI 注入服务的任何组件都有机会订阅 todoList$
可观察对象。
在以下组件中,我们利用异步管道而不是直接订阅 todoList$
可观察对象:
Component.ts
ngOnInit() {
this.todoList$ = this.todoService.todoList$;
}
Component.html
<li class="list-group-item" *ngFor="let item of todoList$ | async">
{{ item.name }}
</li>
每当在服务上调用修改其内部存储的方法时,服务都会更新其所有组件订阅者,而不管哪个组件发起了更改。
Flux 模式是管理复杂 UI 和减少组件之间耦合的优秀模式。而是耦合在Service和Component之间,交互主要是组件订阅服务