Gary Simon Gary Simon - 21 days ago 12
AngularJS Question

Angular 2 Access input value of a different routed component via ngOnInit?


  1. I have a search bar in
    app.component.ts
    that has an input value.

  2. results.component.ts
    is embedded with a router-outlet in
    app.component.html

  3. When
    results.component.ts
    is the current activated route, the search works fine and so do the results.

  4. However, if someone clicks on a result,
    results.component.ts
    is replaced with a different component view
    detail.component.ts
    (it provides them with more information about the result.)

  5. On
    detail.component.ts
    I have a "back to results" link setup with a
    routerLink='/'
    . And mind you, the search query is still present in the search bar because that view never gets replaced.

  6. When this back button is clicked,
    results.component.ts
    reloads and fires
    ngOnInit
    .



The problem: I can't access the value of the search string in
app.component.ts
from
results.component.ts
ngOnInit to repopulate the results. I've tried almost everything I can think of.

I already have a service built, but I don't know how to set it up to communicate that value, if that is the solution.

Updated with code

app.component.html

//other html
<input placeholder="What do you want to learn?" name="searchStr" [(ngModel)]="searchStr" (keyup.enter)="searchCourse($event)">


interaction-service.service.ts:

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


@Injectable()
export class InteractionService {

// Observable string sources
private searchStr = new Subject<string>();

// Observable string streams
searchStr$ = this.searchStr.asObservable();

sendString(searchString: string) {
this.searchStr.next(searchString);
}

}


app.component.ts:

//other imports
import {InteractionService} from './interaction-service.service';

@Component({
selector: 'my-app',
templateUrl: 'app.component.html',
providers: [CourseService, InteractionService]
})

export class AppComponent implements OnInit {

searchStr: string;

constructor(private _courseService: CourseService, private _interactionService: InteractionService, private router: Router) {

}

ngOnInit() {

}

searchCourse(event) {
this._interactionService.sendString(event.target.value);
this.router.navigateByUrl('/');
}

}


course-listings.component.ts (I referred to this as results above)

// other imports
import {Subscription} from 'rxjs';
import {InteractionService} from '../interaction-service.service';

@Component({
selector: 'app-course-listings',
templateUrl: './course-listings.component.html',
providers: [CourseService],
})

export class CourseListingsComponent implements OnInit {

//some other properties defined
@Input() searchStr: string;
subscription: Subscription;

constructor(private _courseService: CourseService, private _interactionService: InteractionService) {

this.subscription = this._interactionService.searchStr$.subscribe(
courses => {
this.searchStr = courses;

// code for returning results here..

}
);

}

ngOnInit() {

}


}

Answer

Your right that you want to use a service. Services are singletons so setting in one component and getting from another will return the passed value.

To get a service to work you need to create the service then add it to your app module. Then in the constructor for your component you add it so the dependency injection can add it to the component for you. The constructor looks like this.

constructor( private router: Router){}

Each component should have a reference in its constructor and the service singleton is shared.

interaction-service.service.ts:

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


@Injectable()
export class InteractionService {
    sharedString = "";
}

app.component.ts:

import {InteractionService} from './interaction-service.service';

@Component({ 
  selector: 'my-app',
  templateUrl: 'app.component.html',
  providers: [CourseService, InteractionService]
})

export class AppComponent implements OnInit { 

constructor(private _courseService: CourseService, private     _interactionService: InteractionService, private router: Router) {

    }

ngOnInit() {
    this.__interactionService.sharedString = "Some value";
}

searchCourse(event) {
    this._interactionService.sendString(event.target.value);
    this.router.navigateByUrl('/');
}

}

I'm going to leave the rest of the code out. The above example should be enough. Simply make the injected interaction service available and set and get the values at will. The service values will persist until there is a browser context change. Last thing I want to mention is when routing call the router like this

this.router.navigate(["url", someParam]);

this will preserve context and not cause a browser context switch when moving between components.