Angular 4:如何使用相同的组件作为父和子?

时间:2017-08-03 12:23:15

标签: angular angular2-routing angular-component-router

我的要求是拥有表单树。在单击按钮的父表单中,将只创建子表单。它可以继续像n级一样。

我的方法:

我创建了一个组件。这用作父母和孩子。点击按钮我动态地将项目添加到ActivatedRoute的route.routeConfig.children。然后导航到相对于当前路径的添加路径。直到这部分一切顺利。 所以我看到scren中的所有形式。我想只在屏幕上显示活动表格。然后单击一个按钮(后退按钮)我想转到它的相关父级并仅显示该表单。我可以在模板中使用* ngif打开子表单时隐藏父表单。但是当孩子回来时却无法看到它。以下是我的代码。如果我应该采取任何其他方法,或者我需要添加额外的方法以使其按照我的方式工作,请告诉我。

我的组件。

@Component({
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.css'],
  providers: [ConfigService]
})
export class TestComponent implements OnInit, OnDestroy {
  name: string;
  age: Number;
  showParent: boolean = true;
  childrenRoute: Routes;
  message: any;
  subscription: Subscription;
  private sub: any;

  constructor(private router: Router, private route: ActivatedRoute, private _configService: ConfigService) {
    this.name = 'test data';
    this.age = 20;
    this.router = router;
    if(this._configService.getConfig('showParent') != null){
      this.showParent=false;
    }
    this.subscription = router.events.subscribe(event => {
      if (event instanceof NavigationEnd) {
        if (_configService.getConfig('showParent') != null) {
          this.showParent =  _configService.getConfig('showParent');
        }
      }

    });


  }

  ngOnInit() {

  }

  ngOnDestroy() {
    // unsubscribe to ensure no memory leaks
    this.subscription.unsubscribe();
  }

  showChildRecord() {
    this.childrenRoute = [{
      path: 'child',
      component: TestComponent
    }];
    if (this.route.routeConfig != undefined) {
      this.route.routeConfig.children = this.childrenRoute;
    }

    this._configService.setOption('showParent', false);
    this.router.navigate(['./child'], { relativeTo: this.route });
  }

  back() {
    this._configService.setOption('showParent', true);
    this.router.navigate(["../"], { relativeTo: this.route });

  }

}

我尝试使用服务在同一组件的每个实例之间共享数据。

@Injectable()
export class ConfigService {
    private config = {};

    setOption(option, value) {
        this.config[option] = value;
    }

    getConfig(option: string) {
        if(option != undefined){
            return this.config[option] != undefined ? this.config[option]: null;
        }else
            return null;
    }

}

模板test.component.html

<div *ngIf="showParent">
<p>Name: 
 <input type="text" [(ngModel)]="name">
</p>
<p>Age:
 <input type="text" [(ngModel)]="age">
</p>
{{name}} : {{age}}
<button  (click)="showChildRecord();" > Go to Child Record</button>
<button (click)="back();">Back</button>
</div>

<router-outlet></router-outlet>

App.module.ts路线:

const appRoutes: Routes = [ 
  { 
    path: 'child',
    component: TestComponent,
    children: [
        { path: 'child', 
          component: TestComponent         
        }
      ]
  }

];

我正在尝试将“showParent”信息存储在服务中并根据操作切换它。在路由事件“NavigationEnd”下,我正在阅读它并将其分配给 showParent propery。但它不起作用。我的父表单仍然是隐藏的。而我只看到空白屏幕。我注意到的一个问题是多次触发“NavigationEnd”事件可能是becoz我正在使用相同的组件,当创建一个新子项时,它会添加另一个事件。

1 个答案:

答案 0 :(得分:0)

我花了一些时间后才能找到上述问题的解决方案。所以想到在这里分享。

所以也有一些错误和一些学问。

我的方法中的错误

  1. 我在testComponent下添加了严格的 ConfigService 。要在所有子组件之间共享相同的服务,我应该在根组件下添加服务。否则,每个组件都有自己的服务实例,数据也会不同。
  2. 意味着

    providers: [ConfigService]
    

    应该添加到AppModule。

    1. 因为它只是一种服务,所以它不会听取价值的变化。所以我应该把它变成一个可观察的。
    2. 因此,我没有使用上述服务,而是创建了另一项服务,如下所示。

      import { Injectable } from '@angular/core';
      import { Observable } from 'rxjs';
      import { Subject } from 'rxjs/Subject';
      
      @Injectable()
      export class MessageService {
          private subject = new Subject<any>();
      
          sendMessage(message: any) {debugger
              this.subject.next(message);
          }
      
          clearMessage() {
              this.subject.next();
          }
      
          getMessage(): Observable<any> {
              return this.subject.asObservable();
          }
      }
      

      在testComponent中,我订阅了它。我只是添加了更改的部分。因此,当我们导航回父路径时, ngOnDestroy 的子进程被调用。这里我们正在使用后来在父进程的订阅回调中捕获的serivce来查找值。

      constructor(private router: Router, private route: ActivatedRoute, private _configService: ConfigService,private _msgService:MessageService) {
          this.name = 'test data';
          this.age = 20;
          this.router = router;
          this.subscription = this._msgService.getMessage().subscribe(message => { 
      
            if(message['showParent']){
              this.showParent=true;
            }
          });
      }
      
         ngOnDestroy() {
          // unsubscribe to ensure no memory leaks  
          this._msgService.sendMessage({ 'showParent':true });
          this.subscription.unsubscribe();
        }
      

      上面的事情解决了从孩子那里得到父母通知的问题。但在我的情况下,因为我可以进入多个级别。单击最后一个子项的返回按钮将触发每个父组件的订阅回调,直到第一个子组件为止。因此,每个父组件都变得可见,而不仅仅是直接父组件。虽然它没有解决我的目的,但我学会了这种跨组件传输数据的方式。也许我可以使用类似路由路径的东西来决定它是否是直接父级。我还没有抓住那个。

      但我必须使用另一种简单的方法来解决我的问题。

      方法2:

      在模板下,我为停用添加了事件监听器。

      <router-outlet (deactivate)='onDeactivateChild($event)' ></router-outlet>
      

      作为TestComponent的一部分,我在下面添加了方法。

      onDeactivateChild(){
          this.showParent=true;
        }
      

      问题解决了。点击后退按钮后,孩子取消激活事件会被触发,父母就会知道它。希望它能帮助面临这个问题的人。

      感谢。