代码之家  ›  专栏  ›  技术社区  ›  Learning is a mess

Angular6:尽管绑定,但查看数据更改时不更新

  •  1
  • Learning is a mess  · 技术社区  · 6 年前

    我用 Angular material table 是的。它基本上是一个递归表,单击一行时显示一个子表,单击一行后显示一个子表。它需要递归模板。表输入数据非常大,采用json格式和json数组等……这种格式是由项目的其余部分决定的,是不灵活的。

    数据存储在一个名为 data 是的。“我的表”中有可修改项的输入字段 数据 我检查了它是否正常工作,我的问题是如果更新 数据 从表外看,表视图没有改变,也没有更新。我很惊讶通过时使用绑定 数据 到组件。我是个角度初学者,不太适应 Subjects Observables 但是,我没有朝那个方向看。

    这是密码。

    对于递归组件:

    @Component({
      selector: 'app-rectable',
      template: `
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    
    <div class="example-container mat-elevation-z8">
      <mat-table [dataSource]="theData">
    
    
        <ng-container matColumnDef="name">
          <mat-header-cell *matHeaderCellDef> channel </mat-header-cell>
          <mat-cell *matCellDef="let element">
            <button *ngIf="element.isexpandable" mat-icon-button (click)="element.isexpanded = !element.isexpanded;">
              <mat-icon class="mat-icon-rtl-mirror">
                {{element.isexpanded ? 'expand_more' : 'chevron_right'}}
              </mat-icon>
            </button>
            <mat-form-field class="example-full-width">
              <input matInput [(ngModel)]="element.name" (input)="update($event)">
            </mat-form-field>
          </mat-cell>
        </ng-container>
    
        <ng-container matColumnDef="min">
          <mat-header-cell *matHeaderCellDef> min </mat-header-cell>
          <mat-cell *matCellDef="let element">
            <input matInput type=number [(ngModel)]="element.min" (input)="update($event)">
          </mat-cell>
        </ng-container>
    
        <ng-container matColumnDef="max">
          <mat-header-cell *matHeaderCellDef> max </mat-header-cell>
          <mat-cell *matCellDef="let element">
            <input matInput type=number [(ngModel)]="element.max" (input)="update($event)">
          </mat-cell>
        </ng-container>
    
        <ng-container matColumnDef="value">
          <mat-header-cell *matHeaderCellDef> value </mat-header-cell>
          <mat-cell *matCellDef="let element">
            {{element.value}}
          </mat-cell>
        </ng-container>
    
        <ng-container matColumnDef="expandedDetail">
          <mat-cell *matCellDef="let detail">
            <app-rectable *ngIf="detail.element.isexpandable" [array]="detail.element.variables" [isTop]="false">
            </app-rectable>
    
          </mat-cell>
        </ng-container>
    
        <div *ngIf="isTop">
        <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
        </div>
        <mat-row *matRowDef="let row; columns: displayedColumns;" matRipple class="element-row" [class.expanded]="row.isexpanded" >
        </mat-row>
        <mat-row *matRowDef="let row; columns: ['expandedDetail']; when: isExpansionDetailRow" [@detailExpand]="row.element.isexpanded ? 'expanded' : 'collapsed'" style="overflow: hidden">
        </mat-row>
      </mat-table>
    </div>
    <div *ngIf="!theData.value.length" > EMPTY DATA INPUT </div>
      `,
      styleUrls: ['./rectable.component.css'],
      animations: [
        trigger('detailExpand', [
          state('collapsed', style({ height: '0px', minHeight: '0', visibility: 'hidden' })),
          state('expanded', style({ height: '*', visibility: 'visible' })),
          transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
        ]),
      ],
    })
    
    export class RectableComponent implements OnInit {
    
      @Input() array;
    
      @Input() isTop: boolean;
      theData = [];
      displayedColumns = ["name", "min", "max", "value"];
      isExpansionDetailRow = (i: number, row: Object) => row.hasOwnProperty('detailRow');
    
      constructor() {
      }
    
      ngOnInit() {
        this.theData = observableOf(this.array);
      }
    
    }
    

    根组件html是

    <app-rectable [array]='data' [isTop]="true"></app-rectable>
    

    在哪里? 数据 是一个json对象,我不希望在这里显式显示。

    3 回复  |  直到 6 年前
        1
  •  3
  •   DavidZ    6 年前

    因为在你的 ngOnInit 你正在改变 data 从一个 Array 变成一个 Observable 是的。

    在你的情况下,因为你必须 [dataSource] ,它需要 dataSource: DataSource<T> | Observable<T[]> | T[] ,只需让父组件通过异步管道将数据传递给子组件。

    起源:

    @Component({
      selector: 'parent-component',
      template: `
    <div>
        <app-rectable [data]="data$ | async" [isTop]="true"></app-rectable>
        ...
    </div>
      `,
    })
    
    export class ParentComponent implements OnInit {
    
        data$: Observable<SomeType[]>;
        constructor(private dataService: DataService) {
        }
    
        ngOnInit() {
            // fetch your data via the service
            this.data$ = this.dataService.fetchData();
        }
     }
    

    儿童:

    @Component({
      selector: 'app-rectable',
      template: `
    <div class="example-container mat-elevation-z8">
      <mat-table [dataSource]="data">
      ...
    </div>
      `,
    })
    
    export class RectableComponent implements OnInit {
    
      @Input() data: SomeType[];
      @Input() isTop: boolean;
    
      displayedColumns = ["name", "min", "max", "value"];
      isExpansionDetailRow = (i: number, row: Object) => row.hasOwnProperty('detailRow');
    
      constructor() {
      }
    }
    
        2
  •  1
  •   Guerric P    6 年前

    我不知道这行的目的是什么 this.theData = observableOf(this.array); ,但这就是破坏你的代码的原因(我认为是什么导致你这样做的,是对角度的误解 @Input() 装饰工和 Observable.of() 用数组的初始值发出一个事件的运算符)。

    这样做,您就从 @Input() array ,因此从父组件更新模板时,模板不会更新,因为它绑定到 theData ,和 数据 仅在组件初始化时设置。

    那么解决方案是:

    • 如果 this.thedata=observateof(this.array); 有真正的目的,然后实施 OnChanges 进入组件并更新 数据 进入之内 ngOnChanges()
    • 如果 this.thedata=observateof(this.array); 没有真正的目的(我坚信它没有),然后完全移除 this.theData 把你的模板绑定到 array
        3
  •  1
  •   molikh    6 年前

    角度2+是单向数据绑定。

    因此,如果更改根目录中的数据,则可以看到组件内部的更改,但当根目录在组件内部更改时,则看不到更改。

    你可以这样做:

    import { EventEmitter} from '@angular/core';
    
    export class YourComponent {
        @Input() item: any;
        @Output() itemChange = new EventEmitter();
      emitItem() {
          this.itemChange.emit(this.item);
      }
    }
    

    这就行了。

      this.itemChange.emit(this.item);
    

    我用这种方式

      <input matInput type=number [(ngModel)]="item" (ngModelChange)="emitItem()" (input)="update($event)">
    

    所以当item changes调用emititem时,我将在根组件中进行更改。

    我希望这能有所帮助。

    推荐文章