【问题标题】:Cannot force render in agular2 from another component无法从另一个组件强制在 aular2 中渲染
【发布时间】:2017-07-17 19:41:13
【问题描述】:

我有以下情况:

组件@permissions 这个组件有一个按钮,可以触发一个简单的承诺并在我的另一个组件上设置一个值@MenuComponent

export class Permissions {
    constructor(private _menu: MenuComponent, private _api: ApiService) {}

    btnAction(){
        this._api.getDataID(item.project_name, 'usersbyID', userID).then((data: any) => {
            this._menu.checkPerm(JSON.parse(data.permissions).description);
        });
    }
}

返回什么并不重要,但它是一个简单的 JSON。

在我的另一个组件@MenuComponent

@Component({
   // ..another configuration non relevant
   changeDetection: ChangeDetectionStrategy.OnPush,
})

export class MenuComponent implements OnInit {
  menus = []
  menuPermisson: any;
  menuObservable = new Subject();

  constructor(private _cdRef: ChangeDetectorRef) {
    this.menuObservable.subscribe(value => {
      this.menuPermisson = value;
      this.reloadAll();
    });
  }

  reloadAll() {
    this.menus.push('someValue');
    this._cdRef.markForCheck();
  }

  checkPerm(data) {
    this.menuObservable.next(data);
  }
}

所以这个概念是在承诺向我的主题发送一些值之后,我需要将 someValue 推送到菜单,直到此时所有数据都可以到达那里,但我需要重新渲染视图,以便“someValue”显示在风景。但它什么也没做,当我将this._cdRef.markForCheck() 更改为this._cdRef.detectChanges() 并将其放在tryCatch 上时,它会返回Attempt to use a destroyed view: detectChanges。我找不到使用 someValue 呈现菜单的方法。

这两个组件在 ChangeDetection 树上处于同一级别

【问题讨论】:

    标签: angular typescript angular2-components angular2-changedetection


    【解决方案1】:

    试试ApplicationRef.tick()。这是“始终有效”的解决方法。

    import { ApplicationRef } from '@angular/core';
    
    export SomeComponent {
        constructor(private appRef: ApplicationRef) {}
    
        public thisShouldCauseChangeDetection(): void {
            this.appRef.tick();
        }
    }
    

    在这里提出了类似的问题:Trigger update of component view from service - No Provider for ChangeDetectorRef

    更多关于ApplicationRef:https://angular.io/api/core/ApplicationRef

    您的问题的最佳解决方案是使用Component <-> Service <-> Component 通信: https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service

    【讨论】:

    • 它继续什么都不做.. 不抛出错误,不渲染视图,但菜单中推送的所有值都在那里。
    • 是否调用了checkPerm() 方法?你把tick()放在哪里了?
    • 是的,它被调用,在reloadAll() 内,如果我在console.log(menus); 内所有数据都在menus 内。
    • 函数的开头还是结尾?您应该更改这些行:this._cdRef.markForCheck(); 和 appRef.tick()
    • 我就是这么做的。
    【解决方案2】:

    我对这个案例的解决方案是来自 Maciej Treder 的建议, 他说:

    '解决您的问题的最佳方法是使用Component <-> Service <-> Component 通信:https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service'

    所以我创建了一个服务来监听@PermissionModule 所做的更改并向@MenuComponent 发送一个更改事件,我可以将vales 推送到menus 数组中并呈现视图,而无需.tick() 或 .detectChanges()

    服务组件

    @Injectable()
    export class SharedServiceMenu {
    
      // Observable string sources
      private emitChangeSource = new Subject<any>();
    
      // Observable string streams
      changeEmitted$ = this.emitChangeSource.asObservable();
    
      // Service message commands
      emitChange(change: any) {
        this.emitChangeSource.next(change);
      }
    
      constructor() { }
    }
    

    我想在哪里发布事件:

    // ...irrelevant code constructor(private: _shared: SharedServiceMenu){} this._shared.emitChange(data);

    我想在哪里听到变化

    // ... IrrelevantCode
    constructor(private _shared: SharedServicesMenu){}
    this._shared.changeEmitted$.subscribe((data) => {
      //Do what ever you want with data emmited here
    }, (err) => {
      console.log(err);
    }, () => {
      console.log('Complete!');
    });
    

    【讨论】:

      【解决方案3】:

      不要在this.menus 中推送值,而是尝试这样的操作

      reloadAll() { 
          var tmp = this.menus.slice();
          tmp.push('some valuue');
          this.menus=tmp;
      }
      

      【讨论】:

      猜你喜欢
      • 2018-12-12
      • 2019-11-19
      • 2019-07-03
      • 2021-12-04
      • 2019-12-09
      • 2019-04-19
      • 2018-01-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多