Angular 2+ testing a component - javascript

I have the following service which make a call to an API :
export class MoviesService {
constructor(private httpClient: HttpClient) { }
// Return an obsevable with all the movies from the API
getAllMovies(): Observable<Movie[]> {
return this.httpClient.get<EmbeddedTitle>("http://localhost:8080/api/movies", { params: params })
.pipe(
map(response => {
return response;
}
));
}
And here's the component that inject that service and call the getAllMovies method:
export class MoviesListingComponent implements OnInit {
public movies: Movie[];
constructor(private moviesService: MoviesService) { }
ngOnInit(): void {
this.getAllMovies();
}
// Subscribe to method service (getAllMovies) and assign the results to a class object (movies)
getAllMovies(): void {
this.moviesService.getAllMovies()
.subscribe(movies => {
this.movies = movies;
});
}
}
I want to know how to unit testing the component's method getAllMovies with Jasmine.

the method getAllMovies() changes the value of your "movies" variable and you component has a dependency to the service that hold the data, your job is mock the service and create a getAllMovies that return dummy data and make sure that your movie field hold the data that you mock

Related

Angular: How to kinda refresh the ngOnInit method

I have a sidebar with different redirects of specific products categories, when these buttons are clicked it redirects to a component that gets the URL params and makes a consult to service and retrieves the data of that specific category, the thing is, when a click it the first time, it works, but the second time it does not, it only changes the URL but does not refresh the data
sidebar.component.html
<div class="list-group">
<a [routerLink]="['products/category']" [queryParams]="{name:category.name}" class="list-group-item"
*ngFor="let category of categories">{{category.name}}</a>
</div>
And the component that makes the magic
export class ViewAllProductsByCategoryComponent implements OnInit {
searchCategory: any;
products: Product;
constructor(private activatedRoute: ActivatedRoute, private productsService: ProductsService) {
}
ngOnInit(): void {
this.activatedRoute.queryParams.subscribe(res => {
this.searchCategory = res.name;
});
this.productsService.searchCategoryProducts(this.searchCategory).subscribe(res => {
this.products = res;
console.log(this.products);
});
}
}
So, how do I refresh the data?
Angular by default doesn't re-initialize an already loaded component.
But there is a way to bypass that feature:
let newLocation = `/pathName/5110`;
// override default re use strategy
this.router
.routeReuseStrategy
.shouldReuseRoute = function () {
return false;
};
this.router
.navigateByUrl(newLocation)
.then(
(worked) => {
// Works only because we hooked
// routeReuseStrategy.shouldReuseRoute
// and explicitly told it don't reuse
// route which forces a reload.
// Otherwise; the url will change but new
// data will not display!
},
(error) => {
debugger;
}
);
Just set the .shouldReuseRoute function to return false, that way the component will reload.
Here's more detail on that topic.
https://dev.to/jwp/angular-s-naviation-challenges-20i2
You can also configure the router to reuse the route.
I've modified a bit john's answer, this is how I fixed it
export class ViewAllProductsByCategoryComponent implements OnInit, OnDestroy {
searchCategory: any;
products: Product;
mySubscription: any;
constructor(private activatedRoute: ActivatedRoute,
private productsService: ProductsService,
private router: Router,
) {
this.router.routeReuseStrategy.shouldReuseRoute = () => {
return false;
};
this.mySubscription = this.router.events.subscribe((event) => {
if (event instanceof NavigationEnd) {
this.router.navigated = false;
}
});
}
ngOnInit(): void {
this.activatedRoute.queryParams.subscribe(res => {
this.searchCategory = res.name;
console.log(this.searchCategory);
});
this.productsService.searchCategoryProducts(this.searchCategory).subscribe(res => {
this.products = res;
console.log(this.products);
});
}
ngOnDestroy(): void {
if (this.mySubscription) {
this.mySubscription.unsubscribe();
}
}
}

How to publish event from a component and receive it from another component in nativescript

How can I publish custom event from a component and receive it from another component in nativescript.
something like:
ComponentOne.ts
this.event.publish('someEvent', {name: 'a name'})
ComponentTwo.ts
this.event.subscribe('someEvent', (data) => {
const name = data.name;
})
You can use subject for this case
import { Injectable } from "#angular/core";
import { Subject } from "rxjs";
#Injectable()
export class MessageService {
private subject = new Subject<any>();
constructor() {}
sendMessage(message: any) {
this.subject.next(message);
}
getData() {
return this.subject.asObservable();
}
}
I defined 2 method here. The first method using next() to send message to the next subcriber. So in your component you just need to simply subscribe like this to get the data
private subscription$: Subscription;
public ngOnInit(): void {
this.subscription$ = this.messageervice
.getData()
.subscribe(data => { console.log(data); })
}
public ngOnDestroy(): void {
this.subscription$.unsubscribe();
}
Found a workaround.
the basic idea is to register a custom event on the root frame of the app and listen on it from the other components
ComponentOne.ts
frameModule.topmost().notify({
eventName: 'punched',
object: frameModule.topmost(),
})
ComponentTwo.ts
frameModule.topmost().on('punched', () => {
console.log('event received');
})

Confusing while Passing data between the components

I am new in angular 6, I am creating the project using angular 6. I am coming to the problem while sharing the data.
Here is my code:
1) Component Sidebar:
selectedCategory(type:any) {
this.loginService.categoryType = type; // need to pass this data
}
2) List Comp:
export class ListPostsComponent implements OnInit {
ngOnInit() {
// here I need the data
}
}
3) Service:
export class LoginService {
categoryType:any;
}
In your service make categoryType a Subject and call the next() when you need to pass data to another component:
#Injectable({
providedIn: 'root',
})
export class LoginService {
private categoryType: Subject<any> = new Subject<any>();
public categoryType$ = this.categoryType.asObservable();
public sendData(data: any){
this.categoryType.next(data);
}
}
Now in your Component Sidebar, you need to inject the service LoginService and call the sendData method:
constructor(private loginService: LoginService ){ }
selectedCategory(type:any) {
this.loginService.sendData(type);
}
Since a Subject is both an Observer and an Observable you can subscribe to the Subject and listen for changes in the component you wish to receive the data:
export class ListPostsComponent implements OnInit {
constructor(private loginService: LoginService ){ }
ngOnInit() {
this.loginService.categoryType$.subscribe((data) => {
//use your data here
});
}
}
Here is a working example of the above solution in Stackblitz: https://stackblitz.com/edit/angular-2sld4k?file=src%2Fapp%2Floginservice.service.ts

Angular 2 send data from component to service

My target is to send data from Angular component to service and use service methods to work on it. Example:
export class SomeComponent {
public data: Array<any> = MyData;
public constructor(private myService: MyService) {
this.myService.data = this.data;
}
}
and service:
#Injectable()
export class TablePageService {
public data: Array<any>;
constructor() {
console.log(this.data);
// undefined
}
}
Getting data is undefined. How to make it works?
An example if interaction between service and component could be:
Service:
#Injectable()
export class MyService {
myMethod$: Observable<any>;
private myMethodSubject = new Subject<any>();
constructor() {
this.myMethod$ = this.myMethodSubject.asObservable();
}
myMethod(data) {
console.log(data); // I have data! Let's return it so subscribers can use it!
// we can do stuff with data if we want
this.myMethodSubject.next(data);
}
}
Component1 (sender):
export class SomeComponent {
public data: Array<any> = MyData;
public constructor(private myService: MyService) {
this.myService.myMethod(this.data);
}
}
Component2 (receiver):
export class SomeComponent2 {
public data: Array<any> = MyData;
public constructor(private myService: MyService) {
this.myService.myMethod$.subscribe((data) => {
this.data = data; // And he have data here too!
}
);
}
}
Explanation:
MyService is managing the data. You can still do stuff with data if you want, but is better to leave that to Component2.
Basically MyService receives data from Component1 and sends it to whoever is subscribed to the method myMethod().
Component1 is sending data to the MyService and that's all he does.
Component2 is subscribed to the myMethod() so each time myMethod() get called, Component2 will listen and get whatever myMethod() is returning.
There is a small issue with the receiver component in #SrAxi s reply as it can't subscribe to the service data. Consider using BehaviorSubject instead of Subject. It worked for me!
private myMethodSubject = new BehaviorSubject<any>("");

Reading routing parameter in HTML

We can set the routing parameter through HTML:
<a [routerLink] = "['/api/foo/', id]"/>
I know that we can read routing parameter through handling event in the typescript:
import {OnInit, OnDestroy, Component} from '#angular/core';
#Component({...})
export class MyComponent implements OnInit{
constructor(private activatedRoute: ActivatedRoute) {}
ngOnInit() {
// subscribe to router event
this.activatedRoute.params.subscribe((params: Params) => {
let Id = params['id'];
console.log(Id);
});
}
}
However, is there any way to read route parameter in the HTML, not in the TypeScript component?
I would like to use in the following manner:
<a href="api/foo/[routerLink]"/>
If you want to get the param in html it is better to assign the param to a variable and use it in html
private param:number;
private ngOnInit() {
// subscribe to router event
this.activatedRoute.params.subscribe((params: Params) => {
this.param = params['id'];
console.log(this.param);
});
}
in your html
<div>{{param}}</div>
if you want to get id as number. You can use this.
id:number;
ngOnInit() {
this.subscription = this.activatedRoute.params.subscribe(
(params: any) => {
if (params.hasOwnProperty('id')) {
id= +params['id'];
//do whatever you want
}
}
);
}
and this destroyed the subscription
ngOnDestroy() {
this.subscription.unsubscribe();
}
and you can access the id field on html side.

Categories

Resources