Binding header to text based on router url (Angular4) - javascript

What's the best way to get header text to change based on the page? I'm currently working from a single header that changes color based on router.url (see previous question here) and I want to change the page header text dynamically.
I feel like the logic should also be similar should I also want to add in images based on the pages as well.
At first I thought to iterate through an array of titles, but that ended up just printing all the titles on all the pages. Then I thought to create a function that check would check the link and return the appropriate title, but I'm not sure how to insert it...
app.component.html
<!-- <div class="set-margin page-title"><h1 *ngFor="let pageTitle of pageTitles">{{ pageTitle.title }}</h1></div> -->
<div class="set-margin page-title">
<!-- <h1 *ngFor="let pageTitle of pageTitles">{{ pageTitle.title }}</h1> -->
<h1>{{ getHeaderText() }}</h1>
</div>
app.component.ts
export class AppComponent {
activatedRoute = '';
title: string;
pageTitles = [
{ 'title': 'About'},
{ 'title': 'Resources'},
{ 'title': 'News' },
{ 'title': 'Contact' }
];
activateRoute(activatedRoute: string) {
this.activatedRoute = activatedRoute;
}
getHeaderText() {
if (this.activatedRoute.includes('about')) {
this.title = 'About';
return this.title;
} else if (this.activatedRoute.includes('resources')) {
this.title = 'Resources';
return this.title;
} else if (this.activatedRoute.includes('newsroom')) {
this.title = 'News';
return this.title;
} else {
this.title = 'Contact';
return this.title;
}
}
constructor(private router: Router) {}
}

You dont need the title or pageTitles. Create a getter property for getting the active page title.
Change your component html to:
<div class="set-margin page-title">
<h1>{{ headerTitle }}</h1>
</div>
... and in your component class:
export class AppComponent {
activatedRoute = '';
activateRoute(activatedRoute: string) {
this.activatedRoute = activatedRoute;
}
get headerTitle {
if (this.activatedRoute.includes('about')) {
return 'About';
} else if (this.activatedRoute.includes('resources')) {
return 'Resources';
} else if (this.activatedRoute.includes('newsroom')) {
return 'News';
} else {
return 'Contact';
}
}
constructor(private router: Router) {}
}

You could pass these titles as data via the router, which would look something like this
{ path: 'about', component: AboutComponent, data: {title: 'About Us'}},
{ path: 'resources', component: AboutComponent, data: {title: 'Amazing Resources'}},
{ path: 'newsroom', component: AboutComponent, data: {title: 'News'}},
app.component.ts
first, be sure to add these imports at the top
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute, Data } from '#angular/router';
then you need to fetch this data from the router. Your AppComponent might look like this
export class AppComponent implements OnInit {
pageTitle = 'default page title';
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.route.data.subscribe(
(data: Data) => {
this.pageTitle = data['title'];
}
);
}
}
then display the data on app.component.html
app.component.html
{{ pageTitle }}

Related

In Angular why will my Dynamic Tabs / Tab Panes work initially but not after update?

I am currently using version 3.4 of CoreUI for my Angular App and I am attempting to use their Tabs setup.
Currently it works fine if I populate the tabs oninit but if I update them it breaks. The entire purpose of being able to use this is to have a dynamic list of tabs and content in those tabs so I am at a loss for why this wouldn't work.
I made a very dumbed down version below to show what I am trying. Note that the first instance of this._tabs works fine, after my await calls when I update to the second version it fails to display correctly.
HTML
<c-card>
<c-card-header>
Tabs <code><small>nav-underline</small></code>
</c-card-header>
<c-card-body>
<c-tabset class="nav-underline nav-underline-primary">
<c-tablist>
<c-tab *ngFor="let tab of tabs" >
{{tab.header}}
</c-tab>
</c-tablist>
<c-tab-content>
<br>
<c-tab-pane *ngFor="let tab of tabs">
<p>
{{tab.panel}}
</p>
</c-tab-pane>
</c-tab-content>
</c-tabset>
</c-card-body>
</c-card>
Component
import { Component, OnInit } from '#angular/core';
import { FormGroup } from '#angular/forms';
import { DbService, DashCpResult, IssuerGroup } from '../../db.service';
import { ActivatedRoute } from '#angular/router';
import { Router } from '#angular/router';
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss']
})
export class DashboardComponent implements OnInit {
// Arrays
DashCpResults: Array<DashCpResult>;
private _setTab: number;
get setTab() {
return this._setTab;
}
set setTab(value: number) {
this._setTab = value || 0;
}
private _tabs: any[] = [];
public get tabs() {
return this._tabs;
}
constructor(
private DbService: DbService,
private route: ActivatedRoute,
private router: Router,
) {
this.setTab = 0;
}
rungetDashCpResult(id) {
return new Promise((resolve) => {
this.DbService.getDashCpResult(id).subscribe(DashCpResults => this.DashCpResults = DashCpResults,
(err) => {
console.log('ERROR: ' + JSON.stringify(err));
},() => {
resolve(1);
});
})
}
async ngOnInit() {
this._tabs = [
{ header: 'Home', panel: 'Home'},
{ header: 'Home2', panel: 'Home2'},
{ header: 'Home3', panel: 'Home3'},
{ header: 'Home4', panel: 'Home4'}
];
// Get Screen detail for Tabs
try { await this.rungetDashCpResult(1); } catch (e) {console.log(e)}
// Update Tabs for a test
this._tabs = [
{ header: 'Home5', panel: 'Home5'},
{ header: 'Home6', panel: 'Home6'},
{ header: 'Home7', panel: 'Home7'},
{ header: 'Home8', panel: 'Home8'}
];
}
}

Integrate Ng-Survey multiple time inside the same component

Im using ng-surveys template inside my angular application
https://ng-surveys.firebaseapp.com/
I put the template selector "" inside *ngFor to make multiple surveys in the same page.
It works but the browser considers all the surveys as the same survey : whene I change something in one survey it changes in the other surveys.
I tried to integrate the template dynamicly using Angular ComponentResolver but I faced many errors and I'm not sure this way can fix my problem.
create-assignment.component.html:
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="card-header">
<i class="fa fa-file-text-o fa-lg"></i> Questionnaires
</div>
<div class="card-body">
<tabset>
<tab *ngFor="let survey of surveys; let i = index">
<ng-template tabHeading><img [src]="survey.category_icon"/> {{survey.category_name}}</ng-template>
<!-- <app-create-survey></app-create-survey> -->
<!-- <ng-template #dynamic></ng-template> -->
<ngs-builder-viewer [options]="options"></ngs-builder-viewer>
</tab>
</tabset>
</div>
</div>
</div>
</div>
create-assignment.component.ts:
import { Component, OnInit, ViewChild, ViewContainerRef, Inject, AfterViewInit, AfterViewChecked } from '#angular/core';
import { LocalStoreService } from '../../../shared/services/local-store.service';
import { ApplicationService } from '../../../shared/services/application.service';
import { NgbDateParserFormatterService } from '../../../shared/services/ngb-date-parser-formatter.service';
import { Router } from '#angular/router';
import { ToastrService } from 'ngx-toastr';
import { IBuilderOptions, NgSurveyState, IElementAndOptionAnswers } from '../../../shared/ng-surveys/models';
import { Observable } from 'rxjs';
import { Survey } from '../../../shared/models/survey';
import { LoaderService } from '../../../shared/services/loader.service';
#Component({
selector: 'app-create-assignment',
templateUrl: './create-assignment.component.html',
styleUrls: ['./create-assignment.component.scss']
})
export class CreateAssignmentComponent implements OnInit, AfterViewChecked {
options: IBuilderOptions;
assignment: any = {};
pending: Boolean = false;
user: any;
shops: any = [];
survey_categories: any = [];
surveys: any = [];
errors: any = {};
service: any
#ViewChild('dynamic', {
read: ViewContainerRef , static: false
}) viewContainerRef: ViewContainerRef
constructor(
#Inject(LoaderService) service,
private ls: LocalStoreService,
public router: Router,
public toastr: ToastrService,
private dateService: NgbDateParserFormatterService,
private appServ: ApplicationService
) {
this.service = service
}
ngAfterViewChecked() {
// this.service.setRootViewContainerRef(this.viewContainerRef)
// this.service.addDynamicComponent()
}
ngOnInit() {
this.options = {
importSurvey: {
callback: this.importSurvey.bind(this),
},
surveyButtons: [{
title: 'Sauvegarder questionnaire',
icon: 'i-Data-Save',
text: 'Sauvegarder',
callback: this.saveSurvey.bind(this),
}],
importElement: {
callback: this.importElement.bind(this),
},
elementButtons: [{
title: 'Sauvegarder question',
icon: 'i-Data-Save',
text: 'Sauvegarder',
callback: this.saveElement.bind(this),
}]
};
this.appServ.getSurveyCategories().subscribe((response: any) => {
this.survey_categories = response.data;
this.survey_categories.forEach(el => {
this.surveys.push(new Survey(el.id, el.name, el.icon, this.options));
});
});
this.user = this.ls.getItem('user');
this.appServ.getBusinessShops(this.user).subscribe((response: any) => {
this.shops = response.data;
});
}
importSurvey(): Observable<NgSurveyState> {
// Mocking get request
return this.getSurvey();
}
importElement(): Observable<IElementAndOptionAnswers> {
// Mocking get request
return this.getElement();
}
getSurvey(): Observable<NgSurveyState> {
return
}
getElement(): Observable<IElementAndOptionAnswers> {
return
}
saveSurvey(ngSurveyState: NgSurveyState): void {
console.log(ngSurveyState);
}
saveElement(element: IElementAndOptionAnswers): void {
// Add post request to save survey data to the DB
console.log('element: ', element);
}
toObject = (map = new Map) =>
Array.from
( map.entries()
, ([ k, v ]) =>
v instanceof Map
? { key: k, value: this.toObject (v) }
: { key: k, value: v }
)
}
I want to make each survey not similar to other surveys
If you look into source code of that library:
In this file projects/ng-surveys/src/lib/ng-surveys.module.ts
These reducers(services) contain survey object:
NgSurveyStore, SurveyReducer, PagesReducer, ElementsReducer, OptionAnswersReducer, BuilderOptionsReducer provided under module level injectors if we can provide these in component level injectors data wouldnt be shared.
Since they are provided in module and when you import in your own module, they are sharing single instance of these reducers which store state survey object.

Data not passing through with route in Angular 6

I have a application with a table of cars:
This is my code:
Carcomponent.html
<tbody>
<tr *ngFor="let car of allCars; index as carId" \>
<td [routerLink]="['/cars', carId]">{{car.carId}}</td>
<td>{{car.brand}}</td>
<td>{{car.model}}</td>
<td>{{car.color}}</td>
<td>{{car.topSpeed }}</td>
</tr>
</tbody>
I have register the route like this:
{ path: 'cars/:carId', component: CardetailsComponent }
And this is my CarDetails.ts file:
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { CarVM } from '../viewmodels/car-vm';
import { CarService } from '../services/car.service';
#Component({
selector: 'app-cardetails',
templateUrl: './cardetails.component.html',
styleUrls: ['./cardetails.component.css']
})
export class CardetailsComponent implements OnInit {
car: any;
carList: any;
constructor(private route: ActivatedRoute, private carservice: CarService) { }
ngOnInit() {
this.route.paramMap.subscribe(params => {
this.car = params.get('carId');
});
}
getCarList() {
this.carList = new CarVM();
this.carservice.getCarById(this.carList.carId).subscribe((res: any) => {
this.carList = res.data;
console.log(this.carList)
})
}
}
And on my Cardetails.html I want to show the selected car like this:
<h2>Car Details</h2>
<div *ngIf="car">
<h3>{{ car.brand }}</h3>
<h4>{{ car.model }}</h4>
<p>{{ car.color }}</p>
</div>
The routing is working fine and fetching the cars is working. Now I want to select one car and see the brand, model, color on the next page. I use a viewmodel for this:
export class CarVM {
CarId: number;
Brand: string;
Model: string;
Color: string;
TopSpeed: number;
}
How can I see the selected car on the next page?
I have followed this tutorial:
https://angular.io/start/routing
Ok, you seem to be bit confused. In cardetails component you want to process carId from route parameters and use it to get car details. You can either get them from server, or have the service return already loaded details of all cars.
Let's say we are trying to make it happen getting the first way, it might look like this:
import { map, switchMap } from 'rxjs/operators';
ngOnInit() {
this.getCar();
}
private getCar(): void {
this.route.paramMap.pipe(
map(params => params.get('carId')),
switchMap(carId => {
return this.carservice.getCarById(carId);
})
).subscribe(
res => {
this.car = res;
console.log('#My car:', this.car);
}
);
}
First, you'll get the carId from route.paramMap, map it using rxjs map, then use switchMap to call you carservice.getCarById(carId) and have it return Observable to which you can subscribe. This should do the trick. Don't forget to properly map it/create CarVM object from it.
The problem is, you don't have CarVM object properly on CardetailsComponent. You are only getting carId into CarVM here: this.car = CarVM[+params.get('carId')];
First you need to create CarVM properly with your class variables. And the you can call your index.
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { CarVM } from '../viewmodels/car-vm';
#Component({
selector: 'app-cardetails',
templateUrl: './cardetails.component.html',
styleUrls: ['./cardetails.component.css']
})
export class CardetailsComponent implements OnInit {
car: any;
carList: any;
constructor(private route: ActivatedRoute) { }
ngOnInit() {
this.route.paramMap.subscribe(params => {
this.car = params.get('carId');
});
}
getCarList(){
this.carList = new CarVM();
//call your service here to fill your carList variable and once you get car list, you will be able to access variable using with your index (this.car).
}
}

On-change ng2-select option load component in dashboard angular4

I am new to Angular 4, I have been working in a project since couple of weeks.
My requirement is when i select a option in ng2-select box i want to load
a separate component in dashboard.
I have created two components to load content based on options in select box.
The first value 0 or first option text should be display default.
When i change options in select i want load two components to respective of their components.
menu.component.html
<ng-select (change)="onChangeSelect($event)" [allowClear]="true"
[items]="items"
[disabled]="disabled"
(data)="refreshValue($event)"
(selected)="selected($event)"
(removed)="removed($event)"
(typed)="typed($event)"
placeholder="Select">
</ng-select>
menu.component.ts
import { Component, OnInit } from '#angular/core';
import * as $ from 'jquery/dist/jquery.min.js';
import {SelectModule} from 'ng2-select';
import { Router} from '#angular/router';
import { ActivatedRoute } from '#angular/router';
declare var jQuery:any;
#Component({
selector: 'app-menu',
templateUrl: './menu.component.html',
styleUrls: ['./menu.component.css'],
})
export class MenuComponent implements OnInit {
onchangeOption:string = '';
public items:Array<string> = ['Program Summary', 'Portfolio Summary']
private value:any = {};
private _disabledV:string = '0';
private disabled:boolean = false;
private get disabledV():string {
return this._disabledV;
}
private set disabledV(value:string) {
this._disabledV = value;
this.disabled = this._disabledV === '1';
}
public selected(value:any):void {
console.log('Selected value is: ', value);
}
public removed(value:any):void {
console.log('Removed value is: ', value);
}
public typed(value:any):void {
console.log('New search input: ', value);
}
public refreshValue(value:any):void {
this.value = value;
}
showHide: boolean;
constructor(private route: ActivatedRoute, private router:Router) {
}
ngOnInit() {
}
showHideMenu(){
this.showHide = !this.showHide;
}
HideMenu(){
this.showHide = false;
console.log("out")
}
onChangeSelect(event){
this.onchangeOption = event.target.value;
console.log(event);
if(this.onchangeOption == 'Portfolio Summary'){
this.router.navigate(['programs']);
}else{
this.router.navigate(['summaries']);
}
}
}
app.module.ts
{
path: 'dashboard',
component: DashboardComponent,
children: [
{ path: '', redirectTo: 'programs', pathMatch: 'full' },
{ path: ':id', component: ProgramsComponent },
/*{ path: 'id', component:ChartsComponent }*/
{ path: 'dashboard/summaries', component:SummariesComponent }
]
}

Resolving data in angular 2

Introduction:
I have a search-box that let's you select a tv show, which then logs the title of the show you clicked, as well as the id for that show. I define this in my:
landingpage.component
<li (click)="selectShow(list.title)" [routerLink]="['/details', list.id]"
*ngFor="let list of shows"> {{list.show}} </li>
When a li is clicked, it sends the list.id as a parameter to my /details component. selectShow just logs the name (list.title) of the show that was clicked.
My problem:
I cannot seem to figure out how to resolve my list.title value, so that it appears in my /details route in this.route.snapshot.data['title']
My code:
app.routing.module.ts
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { TitleResolver } from './services/title.service';
const routes: Routes = [
{ path: '', component: LandingPage },
{
path: 'details/:id', component: ResultPage,
resolve: {
title: TitleResolver //hopefully contains 'title' data here?
}
}
}
];
resultpage.component.ts
title; //variable we will assign to title
constructor(private route: ActivatedRoute) {}
this.route.data
.subscribe((data: { title: Title}) => {
console.log(title);
});
title.service.ts
// this gives us the name of the clicked show
class ShowService {
fetchTitle(title) {
return title;
}
}
#Injectable()
export class TitleResolver {
constructor(private showservice: ShowService) { }
resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<any> | Promise<any> | any {
return this.showservice.fetchTitle(route.params.title);
}
}
My question
What are the intermediate step(s) that I need to do in order to send the selected list.title value from my landingpage.component data to my app.routing.module.ts, so that I can receive it in my resultpage.component ?

Categories

Resources