1

我正在做一个使用 Angular2 创建旅行计划器的小任务。工作流程如下: 用户将输入起点终点以及中间停止点的数量。一旦用户提交“Go”按钮,Planner 表格就会出现,用户可以在其中输入中间停止点以及添加/删除停止点。不知何故,我没有得到所需的输出,如屏幕截图所示。第一个屏幕

第二屏

在添加新的停止点时,这就是我得到的...... 我添加新停止点的输出

期望的输出...... 期望的输出

这就是 Tripdetails 对象的样子。查看对象和视图之间的区别。

控制台图像

代码如下: Trip.ts

export class Trip {
    startPoint:string;
    destination:string;
    stops:number;
}

TripDetails.ts

export class TripDetail {
    startPoint:string;
    destination:string;
}

app.component.ts

import { Component } from '@angular/core';
import { Trip } from './Trip';
import { TripDetail } from './TripDetails';

@Component({
  selector: 'my-app',
  moduleId: module.id,
  templateUrl: 'app.component.html'
})

export class AppComponent  { 
    trip: Trip = {
        startPoint : "",
        destination : "",
        stops : 0
    };
    tripDetails: TripDetail[];

    clicked(startPoint:string, destination:string, stops:string):void {
        let length = parseInt(stops);
            this.trip.startPoint = startPoint;
            this.trip.destination = destination;
            this.trip.stops = length;
            this.tripDetails = [];
        for (let i=0 ; i< length; i++) {
            let tripDetail :TripDetail={
                startPoint: "",
                destination: ""
            }
            if( i==0) {
                tripDetail.startPoint = this.trip.startPoint;
            }
            if( i== length-1) {
                tripDetail.destination = this.trip.destination;
            }
            this.tripDetails.push(tripDetail);
        }
    }

    syncData(index:number, locationType:string) {
        if(locationType == 'destinationLocation') {
            this.tripDetails[index + 1].startPoint = this.tripDetails[index].destination; 

        }
        else if (locationType == 'sourceLocation') {
            this.tripDetails[index - 1].destination = this.tripDetails[index].startPoint; 
        }
    }

    addStop(index:number):void {
        let stop:TripDetail={
            startPoint:"newStop",
            destination:"newStop"
        }
        this.tripDetails.splice(index,0,stop);
    }   

    removeStop(index:number):void{
        let destination = this.tripDetails[index].destination,
            arrlength = this.tripDetails.length;
        if(index==0){
            return;
        }
        else if( index== arrlength-1) {
            this.tripDetails[index-1].destination = this.tripDetails[index].destination;
            this.tripDetails.splice(index,1);
        }
        else{
            this.tripDetails.splice(index,1);
            this.tripDetails[index].destination= destination;   
        }
    }


}

app.component.html

<div class="container content">
    <div>
        <form>
            <label for="startPoint">From:</label>
            <input class="form-control" type="text" placeholder="Enter start point" name="startPoint" [(ngModel)] = "trip.startPoint" >

            <label for="destination">To:</label>
            <input class="form-control" type="text" name="destination" placeholder="Enter destiantion" id="destination" [(ngModel)]="trip.destination" >

            <label for="Stops">Stops:</label>
            <input class="form-control" type="text" placeholder="Enter number of stops"  name="stops" id="stops" [(ngModel)]="trip.stops"  >

            <div class="go-btn">
                <button class="btn btn-primary" (click)="clicked(trip.startPoint,trip.destination,trip.stops)">Go</button>
            </div>
            <div *ngIf = "trip.stops && trip.startPoint && trip.destination" class="trip-table  table-bordered">
                <table class="table table-stripped">
                    <thead class="thead">
                        <tr scope="row">
                        <th>FROM</th><th>TO</th>
                    </tr>
                    </thead>
                    <tr *ngFor= " let stops of tripDetails; let i=index; let first = first; let last= last; trackBy: index ">
                        <td>

                            <input type="text" class="form-control"  name="locationFrom-{{i}}" [(ngModel)]= "stops.startPoint"  (input)="syncData(i, 'sourceLocation')" >
                        </td>
                        <td>

                            <input type="text" class="form-control"  name="locationTo-{{i}}" [(ngModel)]= "stops.destination"  (input)="syncData(i, 'destinationLocation')" >
                        </td>
                        <td>
                            <button class="btn btn-primary" (click)="addStop(i)">+</button>
                        </td>
                        <td>
                            <button class="btn btn-primary" (click)="removeStop(i)" >-</button>
                        </td>
                    </tr>
                </table>                
            </div>
        </form>
    </div>
</div>  

app.module.ts

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule }   from '@angular/forms';

import { AppComponent }  from './app.component';

@NgModule({
  imports:      [ BrowserModule , FormsModule],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }
4

1 回答 1

1

您使用trackBy跟踪索引是绝对正确的,您只是遇到了一些问题。trackby当没有ngModel要跟踪的唯一索引(具有属性的变量,例如[(ngModel)]="myItem.myProperty")时需要,因此在处理原始数组时需要,例如trackBy在下面的示例中需要:

<div *ngFor="let item of items">
  <input [(ngModel)]="item" />
</div>

如果您尝试修改上面的输入字段,输入字段会在输入内容时立即失去焦点。

但你可能会说...

我的数组不是原始类型,我的数组tripDetails包含可以使用唯一ngModel索引跟踪的对象?

诚然,如果您使用表单,那么没有trackBy.

但是由于我们正在处理一个表单,Angular 并不真正关心 unique ngModel,而是查看name属性,这基本上意味着该字段突然没有唯一ngModel的索引来跟踪。

所以使用trackBy

<tr *ngFor= "let stops of tripDetails; let i=index; trackBy:trackByFn">

以及组件中对应的函数:

trackByFn(index: number, stops: string) {
  return index;
}

这是一个

演示

于 2017-04-30T10:26:04.863 回答