Passing values ​​between non-parent / child components in Angular 2

In my opinion, in Angular 2, if you want to pass values ​​between unrelated components (i.e. components that do not share a route and therefore do not have a parent-child relationship), you do this through a shared service.

So what I installed in my application Angular2. I check if a certain series of characters exists in the url and returns true if so.

  isRoomRoute(routeUrl) {
      if ((routeUrl.includes('staff') || routeUrl.includes('contractors'))) {
          console.log('This url: ' + routeUrl + ' is a roomRoute');
          return true;
      } else {
          console.log('This url: ' + routeUrl + ' is NOT a room route');
          return false;
      }
  }

In the constructor of the root app.component, I subscribe to routing events:

constructor(private routeService: RouteService,
            private router: Router)  {
    this.router.events.subscribe((route) => {
    let routeUrl = route.url;
    this.routeService.sendRoute(routeUrl);
    this.routeService.isRoomRoute(routeUrl);
    });
}

... and then using those provided URLs to check if the URL contains a specific string. This is evaluated every time the route changes.

So, everything works as expected.

, ( ) .

, (routeService) app.component, (room.component) , , , . , "" , , , .

, "undefined" , :

  isRoomRoute() {
       if (this.routeService.isRoomRoute(this.routeUrl)) {
           return true;
       }
     }

, . , , URL- , . , . Angular 2?

+4
4

, injectable - .

.

-, Router AppComponent, RouteService, / .

AppComponent:

export class AppComponent {

    constructor(private _router: Router,
                private _routeService: RouteService) {

        this._router.events.subscribe(event => {
            if (event instanceof NavigationEnd) {
                let url = event.urlAfterRedirects;
                this._routeService.onActiveRouteChanged(url);
            }
        });
    }

}

, BehaviorSubject , , , . BehaviorSubject : : EventEmitter Observable Angular2

RouteService ( , , ):

@Injectable()
export class RouteService {

    isRoomRouteSource: BehaviorSubject<boolean> = new BehaviorSubject(false);

    constructor() { }

    onActiveRouteChanged(url: string): void {
        let isRoomRoute = this._isRoomRoute(url);
        this.isRoomRouteSource.next(isRoomRoute);
        // do other stuff needed when route changes
    }

    private _isRoomRoute(url: string): boolean {
        return url.includes('staff') || url.includes('contractors');
    }
}

, , BehaviorSubject:

export class AnotherComponent {

    isCurrentRouteRoomRoute: boolean;

    constructor(private _routeService: RouteService) {
        this._routeService.isRoomRouteSource.subscribe((isRoomRoute: boolean) => {
            this.isCurrentRouteRoomRoute = isRoomRoute;
            // prints whenever active route changes
            console.log('Current route is room route: ', isRoomRoute);
        });
     }

}

isRoomRouteSource , , , :

export class AnotherComponent {

    isCurrentRouteRoomRoute: boolean;

    constructor(private _routeService: RouteService) {
        this.isCurrentRouteRoomRoute = this._routeService.isRoomRouteSource.getValue(); // returns last value stored
        console.log('Current route is room route: ', this.isCurrentRouteRoomRoute);
     }

}

, !

+6

, , - .

  isRoomRoute() {
       if (this.routeService.isRoomRoute(this.routeUrl)) {
           return true;
       }
     }
Hide result
, this.routeUrl , , undefined, . , , - , isRoomRoute .

@Injectable()
class routeService {
  constructor(private router: Router) {
    // subscribe to event
    router.subscribe((url) => {
      this.routeUrl = url;
      // other things?  sendRoute??
    });

  }

  // Other methods for this class
  isRoomRoute() {
    return this.routeUrl && (this.routeUrl.includes('staff') || this.routeUrl.includes('contractors'));
  }
}

// Usage later where this service has been injected
@Component({
 // ... other properties
 providers: [routeService]
})
class someComponent {
  constructor(private routeService: routeService) {}
  someMethod() {
    this.routeService.isRoomRoute();  // Check if we are in a room route.
  }
}
Hide result

, URL- isRoomRoute , - .

+1

( , ):

Angular / :

  • "" EventEmitter ( ).
  • - EventEmitter, - , .

EventEmitters. , , . . , "". , ( - ), , "".

- : , , ( , ). - , , .

, ( MenuBarComponent, "" ):

<ul>
  <li *ngFor="let btn of buttons">
    // Bind the parent broadcast listener, to the child Input. 
    <my-child [broadcastListener]="broadcasterParent">
    </my-child>
  </li>
</ul>

() EventEmitter ( ). , EventEmitter, , , .

, ( , ES6, , , , ):

import { Component, EventEmitter } from '@angular/core';
...
constructor  ) {
  // this is the instance given to the child as Input
  this.broadcasterParent = new EventEmitter ( );
}

:

import { Component } from '@angular/core';
...
  constructor ( ) {
    // This is almost certainly better used in OnInit.
    // It is how the child subscribes to the parent event emitter.
    this.broadcastListener.subscribe( ( b ) => this.onBroadcast ( b ) );
  }

  onButtonClick ( evt ) {
    // Any component anywhere with a ref to this emitter will hear it
    this.broadcastListener.emit ( evt );
  }

  onBroadcast ( evt ) {
    // This will be the data that was sent by whatever button was clicked
    // via the subscription to the Input event emitter (parent, app, etc).
    console.log ( evt );        
}

ChildComponent.annotations = [
  new Component ( {
      ... // TS would use an attribute for this
      inputs: [ 'broadcastListener' ]
      template: `
        <div click)="onButtonClick ( $event )">
           ...
        </div>
      `
  })
];

, "" , ( ..).

, , , , , ( - ).

0

, , , , "" ( / ). , .

EmitService.

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

@Injectable()
export class EmitService {

  private _emitter;

  constructor() {
    this._emitter = new EventEmitter ( );
  }

  subscribeToServiceEmitter ( callback ) {
    return this._emitter.subscribe ( b => callback ( b ) );
  }

  emitThisData ( data ) {
    this._emitter.emit ( data );
  }
}

, . CompOneComponent, , CompTwoComponent:

import { Component, OnInit, OnDestroy } from '@angular/core';
// the CLI puts components in their own folders, adjust this import
// depending on your app structure...
import { EmitService } from '../emit.service';

@Component({
  selector: 'app-comp-one',
  templateUrl: './comp-one.component.html',
  styleUrls: ['./comp-one.component.css']
})
export class CompOneComponent implements OnInit, OnDestroy {

  private _sub;

  constructor( private _emitSvc : EmitService ) {}

  ngOnInit() {
    // A subscription returns an object you can use to unsubscribe
    this._sub = this._emitSvc.subscribeToServiceEmitter ( this.onEmittedEvent );

    // Watch the browser, you'll see the traces. 
    // Give CompTwoComponent a different interval, like 5000
    setTimeout( () => {
      this._emitSvc.emitThisData ( 'DATA FROM COMPONENT_1' );
    }, 2000 );

  }

  onEmittedEvent ( data ) {
    console.log ( `Component One Received ${data}` );
  };

  ngOnDestroy ( ) {
    // Clean up or the emitter callback reference
    this._sub.unsubscribe ( );
  }
}

; , , :

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { CompOneComponent } from './comp-one/comp-one.component';
import { CompTwoComponent } from './comp-two/comp-two.component';

import { EmitService } from './emit.service';

@NgModule({
  declarations: [
    AppComponent,
    CompOneComponent,
    CompTwoComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  exports: [ ],
  providers: [ EmitService ],
  bootstrap: [ AppComponent ]
})
export class AppModule { }

. ( EventEmitter), , , , - . CLI, , , console.log, ( , , , , ). , EmitService, , .

0

Source: https://habr.com/ru/post/1666439/


All Articles