我正在开发一个带有分页的角度应用程序。我的组件包含所有员工的列表。初始化时,它从服务中获取数据。一旦这些数据返回,列表就会更新,我在我的分页方法中使用它。此时,我的应用程序状态已更改,因此我将要更新视图。一切都很好,但有延迟。我只看到F5之后的变化。我不明白,我怎么能告诉Angular在特定时刻更新视图。为了确保在激活路径之前执行任务,我使用解析器,但它仅对第一次渲染有帮助。我明白,问题在于异步数据,但我不明白,如何修复它。请帮我解决这个问题。
我的组件:
@Component({
selector: "paTable",
moduleId: module.id,
templateUrl: "table.component.html",
styleUrls: ["table.component.css"]
})
export class TableComponent implements OnInit{
private allEmployees: Employee[];
pager: any = {};
pagedItems: any[];
constructor(private model: Model, private paginationService: PaginationService){
console.log('constructor');
}
ngOnInit(){
this.allEmployees = this.model.getAllEmployees();
console.log(this.allEmployees);
this.setPage(1);
}
deleteEmployee(key: number) {
this.model.deleteEmployee(key);
}
setPage(page: number){
console.log(page)
if (page < 1 || page > this.pager.totalPages) {
return;
}
// get pager object from service
this.pager = this.paginationService.getPagination(this.allEmployees.length, page);
console.log(this.allEmployees.length);
console.log(this.pager.startIndex);
// get current page of items
this.pagedItems = (this.model.getAllEmployees()).slice(this.pager.startIndex, this.pager.pageSize + 1);
console.log(this.pagedItems);
}
}
我的服务:
@Injectable()
export class Model{
private employees: Employee[] = new Array<Employee>();
private departments: Department[] = new Array<Department>();
constructor(private dataSource: DataSource){
console.log('model');
this.dataSource.getEmployeesData().subscribe(data => this.employees = data);
this.dataSource.getDepsData().subscribe(data => this.departments = data);
}
getAllEmployees(): Employee[]{
return this.employees;
}
getAllDeps(): Department[]{
return this.departments;
}
getEmployee(id: number): Employee{
return this.employees.find(e => e.id == id);
}
saveEmployee(employee: Employee){
if(employee.id == 0 || employee.id == null){
this.dataSource.saveEmployee(employee).subscribe(e => {employee.id = e.insertId; this.employees.push(employee)});
}else{
this.dataSource.updateEmployee(employee).subscribe(() => {
let index = this.employees.findIndex(e => e.id == employee.id);
this.employees.splice(index,1,employee);
});
}
}
}
我的模板:
<tbody>
<tr *ngFor="let item of pagedItems; let i = index">
<td>{{i+1}}</td>
<td>{{item.firstName}}</td>
<td>{{item.lastName}}</td>
<td [ngSwitch] = "item.isActive">
<span *ngSwitchCase ="1">Yes</span>
<span *ngSwitchDefault>No</span>
</td>
<td [ngSwitch] = "item.emp_depID">
<span *ngSwitchCase = "1">HR</span>
<span *ngSwitchCase = "2">Tech</span>
<span *ngSwitchCase = "3">Finance</span>
<span *ngSwitchDefault>No data</span>
</td>
<td>
<button class="btn btn-danger btn-xs" (click)="deleteEmployee(item.id)">
Delete
</button>
</td>
<td>
<button class="btn btn-primary btn-xs" [routerLink]="['/form', 'edit', item.id]">
Edit
</button>
</td>
</tr>
</tbody>
我的解析器:
@Injectable()
export class ModelResolver{
constructor(private model: Model, private dataSource: DataSource,
private messages: MessageService){
}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Employee[]>{
if (this.model.getAllEmployees().length == 0){
this.messages.reportMessage(new Message("Loading data..."));
return this.dataSource.getEmployeesData();
}
}
}
app.routing:
const routes: Routes = [
{ path: "form/:mode/:id", component:FormComponent },
{ path: "form/:mode", component:FormComponent},
{ path: "", component: TableComponent, resolve:{model:ModelResolver} },
]
export const routing = RouterModule.forRoot(routes);
数据源:
@Injectable()
export class DataSource{
constructor(private http: Http, @Inject(URL) private url: string){
console.log('datasource')
}
getEmployeesData(): Observable<Employee[]>{
return this.sendRequest(RequestMethod.Get, `${this.url}employeeslist`);
}
getDepsData(): Observable<Department[]>{
return this.sendRequest(RequestMethod.Get, `${this.url}depslist`);
}
saveEmployee(employee: Employee): Observable<Response>{
return this.sendRequest(RequestMethod.Post, `${this.url}save`, employee);
}
updateEmployee(employee:Employee): Observable<Employee>{
return this.sendRequest(RequestMethod.Put, `${this.url}${employee.id}`, employee);
}
deleteEmployee(id: number): Observable<Employee>{
return this.sendRequest(RequestMethod.Delete, `${this.url}${id}`);
}
private sendRequest(method: RequestMethod, url: string, body?: Employee){
return this.http.request(new Request({
method: method,
url: url,
body: body
})).map(response => response.json());
}
}
答案 0 :(得分:0)
我的“模特”服务看起来更像是这样:
private products: IProduct[];
getProducts(): Observable<IProduct[]> {
if (this.products) {
return of(this.products);
}
return this.http.get<IProduct[]>(this.productsUrl)
.pipe(
tap(data => console.log(JSON.stringify(data))),
tap(data => this.products = data),
catchError(this.handleError)
);
}
当第一个请求进入时,products
属性尚未设置,因此它将获取数据。对于将来的请求,它将返回先前检索的列表。
以这种方式执行,该方法返回一个Observable,因此解析器可以工作。否则该组件可以订阅。
所以:
1)更改您的服务以返回可观察的内容。
订阅组件中的observable。
在检索到数据后,将要执行的代码移动到订阅内。
OR
2)更改您的服务以返回可观察的
使用解析器获取数据
使用组件中的解析器数据。这样,只要组件初始化,数据就可用。
例如,请考虑按如下方式更改代码:
getAllEmployees(): Observable<Employee[]>{
if (this.employees) {
return of(this.employees);
}
return this.dataSource.getEmployeesData();
}
从构造函数中删除调用。
然后你的组件(或你的解析器......不是两者)都可以调用getAllEmployees
方法并取回observable。
例如:
ngOnInit(){
this.model.getAllEmployees().subscribe(
employees => {
console.log(employees);
this.allEmployees = employees;
this.setPage(1);
}
);
}
答案 1 :(得分:0)
我将此添加到单独的答案中,因为先前的答案太长了。除了我之前的答案中概述的模型服务更改,您可以使用解析器的数据,如下所示:
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { IProduct } from './product';
@Component({
templateUrl: './app/products/product-detail.component.html'
})
export class ProductDetailComponent implements OnInit {
pageTitle: string = 'Product Detail';
product: IProduct;
errorMessage: string;
constructor(private route: ActivatedRoute) { }
ngOnInit(): void {
this.product = this.route.snapshot.data['product'];
}
}
请注意,我正在注入ActivatedRoute。然后使用this.route.snapshot.data
读取解析器检索到的数据。
在路由配置中,您将数据命名为model
,因此语法为:
ngOnInit(){
this.allEmployees = this.route.snapshot.data['model'];
console.log(this.allEmployees);
this.setPage(1);
}
答案 2 :(得分:0)
在我的代码中,解析器用于确保在激活路由之前执行任务。在ModelResolver类中调用resolve方法时,它会检查数据模型中的对象数,以确定对服务器的HTTP请求是否已完成。如果数据模型中没有对象,则resolve方法从DataSource返回Observable。因此,在模型填充来自服务器的数据之前,它会阻止用户查看表。我认为问题在于ngOnInit()方法,因为this.model.getAllEmployees();返回一组员工,我将其分配给变量并在我的代码中使用它。当调用ngOnInit()时,异步请求尚未完成,并且我的变量从该方法获取旧数据。新数据到达有一些延迟,所以只有在F5之后,我才能看到我的新结果。我删除了ngOnInit()方法并仅使用我的方法。 这是我的代码。
@Component({
selector: "paTable",
moduleId: module.id,
templateUrl: "table.component.html",
styleUrls: ["table.component.css"]
})
export class TableComponent{
employeesPerPage = 10;
selectedPage = 1;
totalPages: number;
constructor(private model: Model){
}
getAllEmployees(): Employee[]{
let pageIndex = (this.selectedPage - 1)*this.employeesPerPage;
return this.model.getAllEmployees().slice(pageIndex, pageIndex + this.employeesPerPage);
}
getKey(index: number, employee: Employee){
return employee.id;
}
deleteEmployee(key: number) {
this.model.deleteEmployee(key);
}
changePage(newPage: number){
this.selectedPage = newPage;
}
get pageNumbers(): number[]{
this.totalPages = Math.ceil(this.model.getAllEmployees().length/this.employeesPerPage);
let startPage: number;
let endPage: number;
if(this.totalPages <= 10){
startPage = 1;
endPage = this.totalPages;
}else{
if(this.selectedPage <= 6){
startPage = 1;
endPage = 10;
}else if(this.selectedPage + 4 >= this.totalPages){
startPage = this.totalPages-9;
endPage = this.totalPages;
}else{
startPage = this.selectedPage - 5;
endPage = this.selectedPage + 4;
}
}
return new Array((endPage+1) - startPage).fill(0).map((x,i) => i + startPage);
}
}
模板:
<tr *ngFor="let item of getAllEmployees(); let i = index; trackBy:getKey">
<td>{{i+1}}</td>
<td>{{item.firstName}}</td>
<td>{{item.lastName}}</td>
<td [ngSwitch] = "item.isActive">
<span *ngSwitchCase ="1">Yes</span>
<span *ngSwitchDefault>No</span>
</td>
<td [ngSwitch] = "item.emp_depID">
<span *ngSwitchCase = "1">HR</span>
<span *ngSwitchCase = "2">Tech</span>
<span *ngSwitchCase = "3">Finance</span>
<span *ngSwitchDefault>No data</span>
</td>
<td>
<button class="btn btn-danger btn-xs" (click)="deleteEmployee(item.id)">
Delete
</button>
</td>
<td>
<button class="btn btn-primary btn-xs" [routerLink]="['/form', 'edit', item.id]">
Edit
</button>
</td>
</tr>
答案 3 :(得分:0)
如果模型中有对象,我的ModelResolver类中的resolve方法返回null,因为它既不是Observable也不是Promise,Angular会立即激活新路由。所以,在变量this.allEmployees = this.route.snapshot.data [&#39; model&#39;];在我的deleteEmployee或saveEmployee请求之后,我将拥有一系列具有旧数据的员工,因为在初始化时,对服务器的HTTP请求尚未完成。刷新页面时,会显示新结果。