角度6-使用Observable触发兄弟姐妹之间的事件

时间:2018-11-15 11:57:56

标签: angular rxjs

因此,我的应用程序组件中有一个div集合,其中填充了app-cube个组件,父组件中的数组中包含了GridProp个对象,它们的索引表示集合中的每个单元格,意思是我根据array [i]的内容创建每个“单元格”的内容。

在array [i]中,我有一个带有Observable的对象,例如单元格的内容。 当我更新单元格i中的内容时,我想更新单元格[i-1][i+1]的兄弟姐妹

我试图通过让每个app-cube订阅数组中匹配对象中的observable来做到这一点。这样,我应该能够简单地将值发送到数组中任何索引处的观察者,并使其触发已订阅组件的订阅处理程序,对吧?

数组中的对象属于此类

export class GridProp implements OnInit {
  private terrain = new Terrain();
  coord: Array<number>;
  cont: {};

  observer: Observer<string>;
  observable: Observable<string> = new Observable((observer: Observer<string>) => {
    this.observer = observer;
  });
}

然后在cube-component.ts中

@Component({
  selector: 'app-cube',
  templateUrl: './cube.component.html',
  styleUrls: ['./cube.component.css']
})
export class CubeComponent implements OnInit {
  @Input() point; // Represents the relevant GridProp object

  ngOnInit() {
    this.point.observable.subscribe(this.handleCubeUpdate);
  }

  handleCubeUpdate() {
    console.log('handling!');
    this.updateWalls();
  }

  updateWalls() {
    // Do stuff to the "walls" values used in this cube.component.html
  }
  toggleWalls() {
    for (const direction in this.point.cont.terrain.walls) {
      if (this.getSide(direction) && this.getSide(direction).cont.terrain.isBlock) {
        this.point.cont.terrain.walls[direction] = false;
        this.getSide(direction).observer.next(true);
      } else {
        this.point.cont.terrain.walls[direction] = true;
      }
    }
    this.updateWalls();
  }
}

在父组件中,我分散了应用程序多维数据集

<div class="grid-point-z" *ngFor="let z of y">
  <div 
    class="grid-point"
    attr.data-point="{{ z.coord }}" 
    [ngStyle]="{ 
      'z-index': z.coord[2]
      }">
    <app-cube  
      [point]="z"
      [coord]="z"
      [level]="level"
      (click)="clickPoint(z)"
      (change)="onCubeChange($event)">
      {{z}}
    </app-cube>
  </div>
</div>

它因错误而崩溃

ERROR TypeError: this.updateWalls is not a function
    at SafeSubscriber.push../src/app/assets/cube/cube.component.ts.CubeComponent.handleCubeUpdate [as _next] (cube.component.ts:71)

因此,我想它在CubeComponent的订阅中无法识别this.handleCubeUpdate。有解决方法吗?

3 个答案:

答案 0 :(得分:2)

现在,对我而言,我可以在这里尝试回答这个问题更有意义。 希望我能正确表达this:)。

因此,当您在subscribe中传递函数引用时,this中的handleCubeUpdate具有不同的上下文。 您可以将函数实现更改为箭头函数。

handleCubeUpdate = () => {
  this.updateWalls();
}

另外,如果您的updateWalls正在调用另一个函数,则应更改该updateWalls函数箭头功能。

答案 1 :(得分:1)

从我的角度来看,我们遇到了一些设计问题。

在Angular中,组件可以使用它们的@Input()@Output()属性进行交互(输入-要了解父组件和更新视图的更改,输出-要通知其他人内部的更改)

最好将其添加到CubeComponent输出事件somethingChanged中,并在您更新内容时发出此事件。

export class CubeComponent implements OnInit {
  @Input() point; // Represents the relevant GridProp object
  @Output() somethingChanged = new EventEmitter<GridProp>();

  ngOnInit() {
  }

  notifyOthersComponentAboutUpdate() {
    let id = this.point; // You can emit point or some id, to identify it later in parent component
    this.somethingChanged.emit(id);
  }
}

在包含app-component个组件数组的父组件(app-cube)中,创建方法updateSiblings(idOfComponentWhichWasUpdated)并从app-cube组件中调用它

<div class="grid-point-z" *ngFor="let z of y">
  <div 
    class="grid-point"
    attr.data-point="{{ z.coord }}" 
    [ngStyle]="{ 
      'z-index': z.coord[2]
      }">
    <app-cube  
      [point]="z"
      [coord]="z"
      [level]="level"
      (somethingChanged)="updateSiblings($event)">
      {{z}}
    </app-cube>
  </div>
</div>

在该updateSiblings方法中,您可以访问y数组(*ngFor="let z of y"),其中包含app-cube个组件(y: GridProp[])的所有数据。 br /> 您具有已更新的组件ID,因此可以在数组y中找到它,还可以找到其兄弟姐妹并更新其数据。 Angular将自动检测该y数组中的更改,并且您的兄弟姐妹将在UI级别进行更新。

答案 2 :(得分:0)

您是否考虑过在Angular中使用REDUX架构?

Here's a good tutorial了解其运作方式和优势。我使用了完全相同的教程来学习和实现。

然后,您可以将该阵列保留在商店中,并调度操作以更改事物。每个动作都可能包含更新自身的逻辑及其周围的两个项目。