How to update value from Router params inside component? - javascript

I'm using Angular5.
I have Header component.
Goal: I need to implement breadcrumbs in header.
My view:
Routing already implemented, I just need to:
parse ID from URL
get Item from BackEnd
get Name
set Name as Breadcrumb to Header component
My current progress:
I can parse ID from URL using following code:
this.activatedRouter.params.subscribe(params => {
this.id = params['id'];
});
Now, in template I have:
<ul class="breadcrumb">
<li><a routerLink="/items" routerLinkActive="active">Items</a></li>
<li>{{id}}</li>
</ul>
Question: How to update ID value in Component each time after new route executed?
For example:
I'm on Items Page => My URL localhost:4002/items
I clicked on Item, and redirected to Items page => My URL localhost:4002/items/34 => My Breadcrumbs = Items > 34
Thanks in advance

you can use :
constructor( private route: ActivatedRoute) {}
this.route.routerState.params.subscribe(params => {
this.id = params['id'];
});
your component will be updated with the new state

I found solution
constructor(private router: Router) {
this.router.events.subscribe((val: NavigationEnd) => {
...action with val.url variable
}
}
Each time, after redirect you will get data from your URL.

Related

Asynchronous method doesn't work the first time

I'm new in Firebase. I'm using Firestore database and Ionic, I have this problem with an asynchronous call and I can't solve it. Basically in the item variable goes the data that I have saved in the firestore database. But when I want to show them, through a button, in a new html page a strange thing happens, in the url the passed parameter appears and disappears immediately and nothing works anymore. I had a similar problem in the past that I solved using the angular pipe "async" , but in this case it doesn't even work.
In detail, I have a list of items in a component:
ngOnInit() {
this.itemService.getItemsList().subscribe((res)=>{
this.Tasks = res.map((t) => {
return {
id: t.payload.doc.id,
...t.payload.doc.data() as TODO
};
})
});
}
and in item.service.ts I have defined the function:
constructor(
private db: AngularFireDatabase,
private ngFirestore: AngularFirestore,
private router: Router
) { }
getItemsList() {
return this.ngFirestore.collection('items').snapshotChanges();
}
getItem(id: string) {
return this.ngFirestore.collection('items').doc(id).valueChanges();
}
For each item I have a button to show the detail:
<ion-card *ngFor="let item of Tasks" lines="full">
....
<ion-button routerLinkActive="tab-selected" [routerLink]="['/tabs/item/',item.id]" fill="outline" slot="end">View</ion-button>
In component itemsDescription.ts I have:
ngOnInit() {
this.route.params.subscribe(params => {
this.id = params['id'];
});
this.itemService.getItem(this.id).subscribe((data)=>{
this.item=data;
});
}
Finally in html page:
<ion-card-header>
<ion-card-title>{{item.id}}</ion-card-title>
</ion-card-header>
<ion-icon name="pin" slot="start"></ion-icon>
<ion-label>{{item.Scadenza.toDate() | date:'dd/MM/yy'}}</ion-label>
<ion-card-content>{{item.Descrizione}}</ion-card-content>
The Scadenza and Descrizione information are shown, instead id is not. Also the url should be tabs/items/:id but when I click on the button to show the item information, the passed parameter immediately disappears and only tabs/items is displayed. If I remove the data into {{}}, the parameter from the url doesn't disappear
SOLVED
I followed this guide https://forum.ionicframework.com/t/async-data-to-child-page-with-ionic5/184197. So putting ? , for example {{item?.id}} now everything works correctly
Your nested code order not right. You will get the value of id after subscription.
Check this Code:
ngOnInit() {
this.route.params.subscribe(params => {
this.id = params['id'];
this.profileService.getItem(this.id).subscribe((data)=>{
this.item=data;
});
});
}

Refresh List View items when an item added to the Database in Angular+Nativescript

I have an app that saves items in an sqlite database and shows them in a list view.
It loads the listview with the correct data at the beginning of the app, but it doesn't refreshes the listview when I add a new item to the database.
This is the component.ts where I load the items to the observable
export class HomeComponent implements OnInit {
items: ObservableArray<IDataItem>;
constructor(public _itemService: DataService) {
}
ngOnInit(): void {
this.items = this._itemService.selectItems();
}
}
This is the DataService:
export class DataService {
private items = new ObservableArray<IDataItem>();
private database = new DatabaseService();
private db: any;
selectItems(): ObservableArray<IDataItem> {
this.database.getdbConnection()
.then(db => {
db.all("SELECT * FROM items").then(rows => {
for (let row in rows) {
this.items.push({ id: rows[row][0], sitioWeb: rows[row][1], usuario: rows[row][2], password: rows[row][3] });
}
this.db = db;
}, error => {
console.log("SELECT ERROR", error);
});
});
for(let i = 0; i < this.items.length; i++){
Toast.makeText(""+this.items[i].id+" "+this.items[i].sitioWeb+" "+this.items[i].usuario+" "+this.items[i].password,"10")
}
return this.items;
}
getItems(): ObservableArray<IDataItem> {
return this.items;
}
getItem(id: number): IDataItem {
return this.items.filter((item) => item.id === id)[0];
}
}
This is the view where the listview is located at:
<ActionBar class="action-bar">
<Label class="action-bar-title" text="Home"></Label>
</ActionBar>
<GridLayout class="page page-content" >
<ListView [items]="items | async" class="list-group" >
<ng-template let-item="item">
<Label [nsRouterLink]="['../item', item.id]" [text]="item.sitioWeb" class="list-group-item"></Label>
</ng-template>
</ListView>
</GridLayout>
It only loads items to the list view on the init of the app, but I want to refresh it when an item is added.
A simple solution would be to either fire a new request to get the list after you add a new item, or just add it in memory on the front end if you get a success response from the save request. However, while this would work, it's not a great solution. It wouldn't update the list when another user added an item.
I think you should look into using websockets for this. You can have a socket open listening for messages on the front end. The back end would emit a message every time something was added, even if it was added by another user. The front end listener would add that item to the list.
Here is a good tutorial using Sock.js and STOMP to implement websockets in angular.
https://g00glen00b.be/websockets-angular/
You can create sharer service with list of your item like this:
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs';
#Injectable()
export class DataService {
private messageSource = new BehaviorSubject('default message');
currentMessage = this.messageSource.asObservable();
constructor() { }
changeMessage(message: string) {
this.messageSource.next(message)
}
}
Where currentMessage is your list of items. Bind that list to you html and in callback function on create new item call method changeMessage witch will be add new created item in your array.
See this example
And not forget subscribe on changes in your list component.
Once you add a new item to the database you can call selectItems() service which will update the item list whenever new item is added or you can call selectItems() in ngAfterViewChecked() hook as it is executed every time the view of the given component has been checked by the change detection algorithm of Angular. This method executes after every subsequent execution of the ngAfterContentChecked()

Title not changing | Angular 4

I'm trying to override the document title on a route.
This is the route with a default title.
{
path: 'artikel/:id/:slug',
component: ArticleComponent,
data: {title: 'Article', routeType: RouteType.ARTICLE,
description: metaDescription},
resolve: {error: ErrorResolverService, article: ArticleResolveService},
}
I am using an ArticleResolverService to get the article from the ID and then apply a new Title.
resolve(route: ActivatedRouteSnapshot): Observable<Article> {
let id = route.paramMap.get('id');
return this.as.getArticle(id).take(1).map(article => {
if (article) {
//this seems to set the title temporarely (flickering visible)
this.ts.setTitle(article.title);
return article;
}
return null;
});
}
Since this approach doesn't quite work I tried setting the title in the ArticleComponent, which is the target of the route. (This happens in ngOnInit)
this.route.data.subscribe((data:{article: Article}) => {
this.article = data.article;
//this seems to set the title temporarely (flickering visible)
this.ts.setTitle(this.article.title);
//using this in browser console works permanently
window['setTitle'] = (t) => this.ts.setTitle(t);
});
Whatever I am doing, everytime I load the page i see the flickering of the wanted title but then it gets instantly reset to the default title (if I don't use a default title it will just show the page URL in the title bar, also just after flickering of the wanted title).
How do i effectively set a permanent title for this page?
The last step from your question is not required (window['setTitle']). Works just fine with the approach below. The default title will show until the setTitle function is called, then it will stay at the new title
Import Title service
import { Title } from '#angular/platform-browser';
Inject it
constructor(
...
private titleService: Title,
) {...}
Use it in the ngOnInit
this.titleService.setTitle("Some custom title" + this.newInfoFromAPI);

Angular 6 route params reload after Location.go

In order to avoid any component reload I'm using Location.go to change the URL from my first Component (SearchboxComponent).
The thing is that I'm using the route params in a second Component (ListingComponent) to reflect the URL changes in some links, pagination etc. But the new URL is not detected by my subscription and the params don't change. Can I make the router module reparse the URL to fill the new params?
ListingComponent
this.route.params.subscribe( async (params: IListingUrlParams) => {
console.log('params', params);
});
SearchboxComponent
const url = this.parametersService.searchParamsToUrl(params);
// this.router.navigate([url]); This works but reloads my main component
this.listingsService.getList(params); // Fetch the new data before navigation
Location.go(url); // This works but params are not reloaded
If you want to update your current route parameters.
Lets say your route as:
path/:id
Current path : path/123
in component:
import { Location } from '#angular/common';
constructor(private location: Location) { }
updateRoute(){
let url = this.location.path().replace('123', '456');
this.location.go(url);
}
Updated path : path/456

Content not being displayed : Angular 2

I'm working on a feature for my website to provide news feed. To get news feed, I have generated an API key from here : News API. The problem I'm facing is that, I'm not able to display the content in my browser. Let me share my code :
results.component.html
<ul type="none" id="search-options">
<li [class.active_view]="Display('all')" (click)="docClick()">All</li>
<li [class.active_view]="Display('news')" (click)="newsContent()">News</li>
<li [class.active_view]="Display('images')" (click)="imageClick()">Images</li>
<li [class.active_view]="Display('videos')" (click)="videoClick()">Videos</li>
</ul>
In results.component.html, it has 4 tabs. In tabs with name : All, Image, Video - I'm getting data from the server from which the desired results are fetched based on query. But in News tab, I'm trying to integrate it with the API which I have mentioned above. Clicking on that tab, should show news feed (just keeping it simple). But, it does not displays anything when news tab is clicked. (No console errors) However, if I use html repeater, how I'm going to use it here ?
news.component.ts
newsFeed: {};
resultDisplay: string;
constructor(private _newsService: NewsService) {}
Display(S) {
return (this.resultDisplay === S);
}
newsContent() {
this.resultDisplay = 'news';
this._newsService.getNews().subscribe(data => {
this.newsFeed = Object.assign({}, data);
});
}
news.service.ts
import { Injectable } from '#angular/core';
import { Http, Jsonp } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class NewsService {
public generalNews: string = 'https://newsapi.org/v1/articles?source=bbc-news&sortBy=top&apiKey=abc123';
constructor(
private http: Http,
private jsonp: Jsonp
) { }
getNews() {
return this.http.get(this.generalNews).map(response => {
response.json()
});
}
}
It would be great if anybody can point out what mistake I'm doing and provide me the solution to improve it. Thanks in advance. :)
Based on what I got from your question. You should do the following.
Have a repeater on your html first. Something like:
<div *ngFor = "let news of newsList">
<p> {{news}} </p>
</div>
This way you can iterate the news array on your html one news at a time.
Next thing, is getting the response and passing it to the view. I am assuming you get the news on click of <li>, as that is all your view presently contains. So in your component you should have
private newsList: any[] = [] //initializing a blank list of type any.
newsContent() {
this.resultDisplay = 'news'; //not sure why you need this, but let it be for now
this._newsService.getNews().subscribe(data => {
this.newsList = data; //assuming data is the actual news array, if the data is entire response you might have to go for data.data
});
}
This way your newsList variable is populated and will be iterated on the html. May be you might have to make few adjustment but it should help you start.
Let me know if it helps or any further issue faced.
Few more changes would be required based on your response:
First : return data from your service method like:
getNews() {
return this.http.get(this.generalNews).map(response:any => {
return response.json()
});
}
Second, your data contains news in article array. So use that instead:
newsContent() {
this.resultDisplay = 'news'; //not sure why you need this, but let it be for now
this._newsService.getNews().subscribe(data => {
this.newsList = data.article; //assuming data is the actual news array, if the data is entire response you might have to go for data.data
});
}
Next edit your html to bind a particular field of your news. I am binding title you can bind one or more that you like:
<div *ngFor = "let news of newsList">
<p> {{news.title}} </p>
</div>
Try this. should work now.
You have missed return statement return response.json().
news.service.ts
import { Injectable } from '#angular/core';
import { Http, Jsonp } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class NewsService {
public generalNews: string = 'https://newsapi.org/v1/articles?source=bbc-news&sortBy=top&apiKey=abc123';
constructor(
private http: Http,
private jsonp: Jsonp
) { }
getNews() {
return this.http.get(this.generalNews).map(response => {
return response.json();
});
}
}

Categories

Resources