我怎样才能保持我的Angular 2应用程序的进展状态的对话框? [英] How can I maintain the state of dialog box with progress all over my Angular 2 application?

查看:186
本文介绍了我怎样才能保持我的Angular 2应用程序的进展状态的对话框?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想保持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触发的动作:


这是一个实现Flux架构的ToDoService示例: p>

 从'@ angular / core'导入{Injectable}; 
从'@ angular / http'导入{Http};
从'rxjs / Rx'导入{BehaviorSubject,Observable};
导入'rxjs / add / operator / toPromise';

导出界面ToDo {
id:number;
名称:string;
isComplete:boolean;
日期:日期;

$ b b @Injectable()
export class ToDoService {
public todoList $:Observable< ToDo []> ;;
private subject:BehaviorSubject< ToDo []> ;;
私人商店:{
todos:ToDo [];


public constructor(private http:Http){
this.subject = new BehaviorSubject< ToDo []>([]);
this.todoList $ = this.subject.asObservable();
this.store = {
todos:[]
};

$ b $ public remove(todo:ToDo){
this.http.delete(`http:// localhost / todoservice / api / todo / $ {todo.id} (t,i)=>
.subscribe(t => {
this.store.todos.forEach((t,i)=> {
if(t.id === todo.id ){this.store.todos.splice(i,1);}
});
让copy = this.copy(this.store).todos;
this.subject.next (副本);

});
}

公共更新(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;


$ b 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);

}); (t:T):T {
返回Object.assign({},t); $ {
}

private copy< T>





有几点需要注意此服务:


  • 服务存储数据存储的缓存副本 {todos:ToDo []}

  • 它暴露了组件可以订阅的Observable(如果他们感兴趣)
  • 它使用一个私有的BehaviourSubject其实施。订阅时,BehaviorSubject将发出初始值。如果你想用一个空数组来初始化Observable,那么这很方便。
  • 每当一个方法被调用来改变数据存储(删除或者更新)时,服务就会生成一个web服务调用来更新其持久性存储,然后在发布更新的 ToDo [] 列表之前更新其缓存的数据存储

  • <数据从服务发出,以防止意外的数据变化向相反的方向传播(这对维持通量模式很重要)。 li>


DI注入服务的任何组件都有机会订阅 todoList $

在下面的组件中,我们利用异步管道而不是订阅 todoList $ observable直接:

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并减少组件之间耦合的极佳模式。相反,耦合是在服务和组件之间,而交互主要是为组件订阅服务。


I would like to keep the state of the Md Dialog alive even I close the dialog.So that I can keep the upload status active all over the application. My plan is to store the upload response in the service to maintain the upload progress and an icon will be given in the toolbar.The dialog box reinitializes everytime. How can I maintain the state of dialog box with upload progress all over the application?

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>

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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆