Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 角度2同级组件通信_Javascript_Angular_Typescript - Fatal编程技术网

Javascript 角度2同级组件通信

Javascript 角度2同级组件通信,javascript,angular,typescript,Javascript,Angular,Typescript,我有一个列表组件。在ListComponent中单击某个项目时,该项目的详细信息应显示在DetailComponent中。两者同时出现在屏幕上,因此不涉及路由 如何告诉DetailComponent单击了ListComponent中的哪个项目 我考虑向父级(AppComponent)发出一个事件,并让父级在DetailComponent上使用@Input设置selectedItem.id。或者我可以使用具有可观察订阅的共享服务 编辑:通过event+@Input设置所选项目不会触发Detail

我有一个列表组件。在ListComponent中单击某个项目时,该项目的详细信息应显示在DetailComponent中。两者同时出现在屏幕上,因此不涉及路由

如何告诉DetailComponent单击了ListComponent中的哪个项目

我考虑向父级(AppComponent)发出一个事件,并让父级在DetailComponent上使用@Input设置selectedItem.id。或者我可以使用具有可观察订阅的共享服务


编辑:通过event+@Input设置所选项目不会触发DetailComponent,以防我需要执行其他代码。所以我不确定这是一个可以接受的解决方案


但这两种方法似乎都比通过$rootScope.$broadcast或$scope.$parent.$broadcast的角度1方式复杂得多

Angular 2中的所有内容都是一个组件,我很惊讶没有更多关于组件通信的信息

是否有其他/更直接的方法来实现这一点

我很惊讶没有更多关于组件通信的信息

对于兄弟组件通信,我建议使用
sharedService
。不过,还有其他选择

import {Component,bind} from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser';
import {HTTP_PROVIDERS} from 'angular2/http';
import {NameService} from 'src/nameService';


import {TheContent} from 'src/content';
import {Navbar} from 'src/nav';


@Component({
  selector: 'app',
  directives: [TheContent,Navbar],
  providers: [NameService],
  template: '<navbar></navbar><thecontent></thecontent>'
})


export class App {
  constructor() {
    console.log('App started');
  }
}

bootstrap(App,[]);
从'angular2/core'导入{Component,bind};
从'angular2/platform/browser'导入{bootstrap};
从'angular2/HTTP'导入{HTTP_提供者};
从'src/NameService'导入{NameService};
从'src/content'导入{TheContent};
从'src/nav'导入{Navbar};
@组成部分({
选择器:“应用程序”,
指令:[内容,导航栏],
提供者:[名称服务],
模板:“”
})
导出类应用程序{
构造函数(){
log(“应用程序启动”);
}
}
引导(应用程序,[]);
有关更多代码,请参阅顶部的链接


编辑:这是一个非常小的演示。您已经提到您已经尝试了
sharedService
。因此,请了解更多信息

更新为rc.4: 在angular2中尝试在兄弟组件之间传递数据时,目前最简单的方法(angular.rc.4)是利用angular2的层次依赖注入并创建共享服务

服务内容如下:

import {Injectable} from '@angular/core';

@Injectable()
export class SharedService {
    dataArray: string[] = [];

    insertData(data: string){
        this.dataArray.unshift(data);
    }
}
现在,这里是父组件

import {Component} from '@angular/core';
import {SharedService} from './shared.service';
import {ChildComponent} from './child.component';
import {ChildSiblingComponent} from './child-sibling.component';
@Component({
    selector: 'parent-component',
    template: `
        <h1>Parent</h1>
        <div>
            <child-component></child-component>
            <child-sibling-component></child-sibling-component>
        </div>
    `,
    providers: [SharedService],
    directives: [ChildComponent, ChildSiblingComponent]
})
export class parentComponent{

} 
import { Subscription } from 'rxjs/Subscription';
import { CallService } from "../../../services/call.service";


ngOnInit() {

 this.subscription = this.Util.getClickCall().subscribe(message => {

 this.message = message;

 console.log('---button clicked at another component---');

 //call you action which need to execute in this component on button clicked

 });

}

import { Subscription } from 'rxjs/Subscription';
import { CallService } from "../../../services/call.service";


ngOnInit() {

 this.subscription = this.Util.getClickCall().subscribe(message => {

 this.message = message;

 console.log('---button clicked at another component---');

 //call you action which need to execute in this component on button clicked

});

}
从'@angular/core'导入{Component};
从“/shared.service”导入{SharedService};
从“./child.component”导入{ChildComponent};
从“./child sibling.component”导入{ChildSiblingComponent};
@组成部分({
选择器:“父组件”,
模板:`
父母亲
`,
提供者:[共享服务],
指令:[ChildComponent,ChildSiblingComponent]
})
导出类parentComponent{
} 
还有它的两个孩子

儿童1

import {Component, OnInit} from '@angular/core';
import {SharedService} from './shared.service'

@Component({
    selector: 'child-component',
    template: `
        <h1>I am a child</h1>
        <div>
            <ul *ngFor="#data in data">
                <li>{{data}}</li>
            </ul>
        </div>
    `
})
export class ChildComponent implements OnInit{
    data: string[] = [];
    constructor(
        private _sharedService: SharedService) { }
    ngOnInit():any {
        this.data = this._sharedService.dataArray;
    }
}
从'@angular/core'导入{Component,OnInit};
从“./shared.service”导入{SharedService}
@组成部分({
选择器:'子组件',
模板:`
我是一个孩子

  • {{data}}
  • ` }) 导出类ChildComponent实现OnInit{ 数据:字符串[]=[]; 建造师( 私有_sharedService:sharedService{} ngOnInit():任何{ this.data=this.\u sharedService.dataArray; } }
    孩子2(它的兄弟姐妹)

    从'angular2/core'导入{Component};
    从“./shared.service”导入{SharedService}
    @组成部分({
    选择器:“子同级组件”,
    模板:`
    我是一个孩子
    `
    })
    导出类ChildSiblingComponent{
    数据:字符串=‘测试数据’;
    建造师(
    私有_sharedService:sharedService{}
    addData(){
    this.\u sharedService.insertData(this.data);
    这个数据=“”;
    }
    }
    
    现在:使用此方法时需要注意的事项

  • 仅在父组件中包括共享服务的服务提供程序,而不包括子组件
  • 您仍然必须包含构造函数并在子类中导入服务
  • 这个答案最初是针对早期angular 2 beta版本的。不过,所有的更改都是import语句,因此如果您碰巧使用了原始版本,那么这就是您需要更新的全部内容

  • 您需要设置组件之间的父子关系。问题在于,您可能只需将子组件注入父组件的构造函数中,并将其存储在局部变量中。 相反,您应该使用
    @ViewChild
    属性声明器在父组件中声明子组件。 这就是父组件的外观:

    import { Component, ViewChild, AfterViewInit } from '@angular/core';
    import { ListComponent } from './list.component';
    import { DetailComponent } from './detail.component';
    
    @Component({
      selector: 'app-component',
      template: '<list-component></list-component><detail-component></detail-component>',
      directives: [ListComponent, DetailComponent]
    })
    class AppComponent implements AfterViewInit {
      @ViewChild(ListComponent) listComponent:ListComponent;
      @ViewChild(DetailComponent) detailComponent: DetailComponent;
    
      ngAfterViewInit() {
        // afther this point the children are set, so you can use them
        this.detailComponent.doSomething();
      }
    }
    
    从'@angular/core'导入{Component,ViewChild,AfterViewInit};
    从“./list.component”导入{ListComponent};
    从“./detail.component”导入{DetailComponent};
    @组成部分({
    选择器:“应用程序组件”,
    模板:“”,
    指令:[ListComponent,DetailComponent]
    })
    类AppComponent实现AfterViewInit{
    @ViewChild(ListComponent)ListComponent:ListComponent;
    @ViewChild(DetailComponent)DetailComponent:DetailComponent;
    ngAfterViewInit(){
    //在这一点之后,孩子们被设置好了,所以你可以使用他们
    this.detailComponent.doSomething();
    }
    }
    

    注意,在调用
    ngAfterViewInit
    lifecyclehook之后,子组件在父组件的构造函数中将不可用。要捕获这个钩子,只需在父类中实现
    AfterViewInit
    接口,方法与
    OnInit
    相同

    但是,还有其他属性声明程序,如本博客注释所述:

    如果有两个不同的组件(不是嵌套组件,而是父组件\
    import { Injectable } from '@angular/core';
    import { Subject }    from 'rxjs/Subject';
    
    @Injectable()
    
    export class MissionService {
      // Observable string sources
      private missionAnnouncedSource = new Subject<string>();
      private missionConfirmedSource = new Subject<string>();
      // Observable string streams
      missionAnnounced$ = this.missionAnnouncedSource.asObservable();
      missionConfirmed$ = this.missionConfirmedSource.asObservable();
      // Service message commands
      announceMission(mission: string) {
        this.missionAnnouncedSource.next(mission);
      }
      confirmMission(astronaut: string) {
        this.missionConfirmedSource.next(astronaut);
      }
    
    }
    
    import { Component, Input, OnDestroy } from '@angular/core';
    import { MissionService } from './mission.service';
    import { Subscription }   from 'rxjs/Subscription';
    @Component({
      selector: 'my-astronaut',
      template: `
        <p>
          {{astronaut}}: <strong>{{mission}}</strong>
          <button
            (click)="confirm()"
            [disabled]="!announced || confirmed">
            Confirm
          </button>
        </p>
      `
    })
    export class AstronautComponent implements OnDestroy {
      @Input() astronaut: string;
      mission = '<no mission announced>';
      confirmed = false;
      announced = false;
      subscription: Subscription;
      constructor(private missionService: MissionService) {
        this.subscription = missionService.missionAnnounced$.subscribe(
          mission => {
            this.mission = mission;
            this.announced = true;
            this.confirmed = false;
        });
      }
      confirm() {
        this.confirmed = true;
        this.missionService.confirmMission(this.astronaut);
      }
      ngOnDestroy() {
        // prevent memory leak when component destroyed
        this.subscription.unsubscribe();
      }
    }
    
    <!-- Assigns "AppSibling1Component" instance to variable "data" -->
    <app-sibling1 #data></app-sibling1>
    <!-- Passes the variable "data" to AppSibling2Component instance -->
    <app-sibling2 [data]="data"></app-sibling2> 
    
    import { AppSibling1Component } from '../app-sibling1/app-sibling1.component';
    ...
    
    export class AppSibling2Component {
       ...
       @Input() data: AppSibling1Component;
       ...
    }
    
    import { BehaviorSubject } from 'rxjs/BehaviorSubject';
    private noId = new BehaviorSubject<number>(0); 
      defaultId = this.noId.asObservable();
    
    newId(urlId) {
     this.noId.next(urlId); 
     }
    
    public getId () {
      const id = +this.route.snapshot.paramMap.get('id'); 
      return id; 
    }
    
    ngOnInit(): void { 
     const id = +this.getId ();
     this.taskService.newId(id) 
    }
    
    delete(task: Task): void { 
      //we save the id , cuz after the delete function, we  gonna lose it 
      const oldId = task.id; 
      this.taskService.deleteTask(task) 
          .subscribe(task => { //we call the defaultId function from task.service.
            this.taskService.defaultId //here we are subscribed to the urlId, which give us the id from the view task 
                     .subscribe(urlId => {
                this.urlId = urlId ;
                      if (oldId == urlId ) { 
                    // Location.call('/home'); 
                    this.router.navigate(['/home']); 
                  } 
              }) 
        }) 
    }
    
    @Directive({
        selector: '[ytPlayerPlayButton]'
    })
    export class YoutubePlayerPlayButtonDirective {
    
        _player: YoutubePlayerComponent; 
    
        @Input('ytPlayerVideo')
        private set player(value: YoutubePlayerComponent) {
           this._player = value;    
        }
    
        @HostListener('click') click() {
            this._player.play();
        }
    
       constructor(private elementRef: ElementRef) {
           // the button itself
       }
    }
    
    <youtube-player #technologyVideo videoId='NuU74nesR5A'></youtube-player>
    
    ... lots more DOM ...
    
    <button class="play-button"        
            ytPlayerPlayButton
            [ytPlayerVideo]="technologyVideo">Play</button>
    
    import { Observable } from 'rxjs';
    import { Subject } from 'rxjs/Subject';
    
    @Injectable()
    export class CallService {
     private subject = new Subject<any>();
    
     sendClickCall(message: string) {
        this.subject.next({ text: message });
     }
    
     getClickCall(): Observable<any> {
        return this.subject.asObservable();
     }
    }
    
    import { CallService } from "../../../services/call.service";
    
    export class MarketplaceComponent implements OnInit, OnDestroy {
      constructor(public Util: CallService) {
    
      }
    
      buttonClickedToCallObservable() {
       this.Util.sendClickCall('Sending message to another comp that button is clicked');
      }
    }
    
    import { Subscription } from 'rxjs/Subscription';
    import { CallService } from "../../../services/call.service";
    
    
    ngOnInit() {
    
     this.subscription = this.Util.getClickCall().subscribe(message => {
    
     this.message = message;
    
     console.log('---button clicked at another component---');
    
     //call you action which need to execute in this component on button clicked
    
     });
    
    }
    
    import { Subscription } from 'rxjs/Subscription';
    import { CallService } from "../../../services/call.service";
    
    
    ngOnInit() {
    
     this.subscription = this.Util.getClickCall().subscribe(message => {
    
     this.message = message;
    
     console.log('---button clicked at another component---');
    
     //call you action which need to execute in this component on button clicked
    
    });
    
    }
    
    @NgModule({
        imports: [
            ...
        ],
        bootstrap: [
            AppComponent
        ],
        declarations: [
            AppComponent,
        ],
        providers: [
            SharedService,
            ...
        ]
    });
    
    constructor(private sharedService: SharedService)
     
    
    @Injectable()
    export class SharedService {
        public clickedItemInformation: Subject<string> = new Subject(); 
    }
    
    this.sharedService.clikedItemInformation.next("something");
    
    this.sharedService.clikedItemInformation.subscribe((information) => {
        // do something
    });
    
    @Component({
        selector: 'parent',
        template: `<div><notes-grid 
                [Notes]="(NotesList$ | async)"
                (selectedNote)="ReceiveSelectedNote($event)"
            </notes-grid>
            <note-edit 
                [gridSelectedNote]="(SelectedNote$ | async)"
            </note-edit></div>`,
        styleUrls: ['./parent.component.scss']
    })
    export class ParentComponent {
    
        // create empty observable
        NotesList$: Observable<Note[]> = of<Note[]>([]);
        SelectedNote$: Observable<Note> = of<Note>();
    
        //passed from note-grid for selected note to edit.
        ReceiveSelectedNote(selectedNote: Note) {
        if (selectedNote !== null) {
            // change value direct subscribers or async pipe subscribers will get new value.
            this.SelectedNote$ = of<Note>(selectedNote);
        }
        }
        //used in subscribe next() to http call response.  Left out all that code for brevity.  This just shows how observable is populated.
        onNextData(n: Note[]): void {
        // Assign to Obeservable direct subscribers or async pipe subscribers will get new value.
        this.NotesList$ = of<Note[]>(n.NoteList);  //json from server
        }
    }
    
    //child 1 sibling
    @Component({
      selector: 'note-edit',
      templateUrl: './note-edit.component.html', // just a textarea for noteText and submit and cancel buttons.
      styleUrls: ['./note-edit.component.scss'],
      changeDetection: ChangeDetectionStrategy.OnPush
    })
    export class NoteEditComponent implements OnChanges {
      @Input() gridSelectedNote: Note;
    
        constructor() {
        }
    
    // used to capture @Input changes for new gridSelectedNote input
    ngOnChanges(changes: SimpleChanges) {
         if (changes.gridSelectedNote && changes.gridSelectedNote.currentValue !== null) {      
          this.noteText = changes.gridSelectedNote.currentValue.noteText;
          this.noteCreateDtm = changes.gridSelectedNote.currentValue.noteCreateDtm;
          this.noteAuthorName = changes.gridSelectedNote.currentValue.noteAuthorName;
          }
      }
    
    }
    
    //child 2 sibling
    
    @Component({
        selector: 'notes-grid',
        templateUrl: './notes-grid.component.html',  //just an html table with notetext, author, date
        styleUrls: ['./notes-grid.component.scss'],
        changeDetection: ChangeDetectionStrategy.OnPush
    })
    export class NotesGridComponent {
    
    // the not currently selected fromt eh grid.
        CurrentSelectedNoteData: Note;
    
        // list for grid
        @Input() Notes: Note[];
    
        // selected note of grid sent out to the parent to send to sibling.
        @Output() readonly selectedNote: EventEmitter<Note> = new EventEmitter<Note>();
    
        constructor() {
        }
    
        // use when you need to send out the selected note to note-edit via parent using output-> input .
        EmitSelectedNote(){
        this.selectedNote.emit(this.CurrentSelectedNoteData);
        }
    
    }
    
    
    // here just so you can see what it looks like.
    
    export interface Note {
        noteText: string;
        noteCreateDtm: string;
        noteAuthorName: string;
    }