Or: things I have implemented multiple times while developing in Angular 2 / Angular 6. Mostly for my own reference, but if it helsp someone else, great. This is a living post that I will add to and edit as I continue to develop in Angular without necessarily timestamping changes.
Breadcrumbs
<a [routerLink]="['/interface-client']">All Clients</a> > <a [routerLink]="['/interface-client/', id]">{{ client.name }}</a>
Display Scrollbar while Bootstrap Modal is open
.modal-open
{
overflow-y: scroll;
}
Monitor how Bootstrap Modal was closed from parent
parent.component.ts
openModal() {
const modalRef = this.modalService.open(ConfirmModalComponent); // Open modal
modalRef.componentInstance.model = this.model; // Pass object to modal
// Change the variable submitted based on how the modal was closed
modalRef.result.then(value => { this.submitted = value === 'submitted' ? true : false; });
}
confirm-modal.component.ts:
onSubmit() {
this.dataService.newApp(this.model);
this.activeModal.close('submitted');
}
onCancel() {
this.activeModal.close('canceled');
}
Dynamically Change Dropdown Contents (Angular Forms)
Say I have two dropdown elements in the form of select tags, one with id “species” and the other with id “name”. I want the available names to change based on the species currently selected, and I never want either dropdown to be blank.
More good advice: KastePanyan24 on Medium
Here is a working example on stackblitz.
app.component.html
<h3>INPUT:</h3>
<form *ngIf="formReady === true">
<div class="form-group">
<label for="species">Species: </label>
<select class="form-control"
id="species"
(change)="onChange($event.target.value)"
[(ngModel)]="model.species"
name="f_species">
<option *ngFor="let species_singular of species" [value]="species_singular">
{{ species_singular }}
</select>
</div>
<div class="form-group">
<label for="name">Name: </label>
<select class="form-control"
id="name"
[(ngModel)]="model.name"
name="f_name">
<option *ngFor="let name of appropriateNames" [value]="name.name">
{{ name.name }}
</select>
</div>
</form>
<h3>OUTPUT:</h3>
<pre>{{ model.species }}, {{ model.name }}</pre>
app.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
/* The model the form begins with. */
model = { species: 'cat', name: 'spot' }
/* Our data */
species: string[] = ['cat', 'dog'];
names = [
{ species: 'cat', name: 'smokey' },
{ species: 'cat', name: 'spot' },
{ species: 'dog', name: 'kobe' },
{ species: 'dog', name: 'cheddar' }
];
/* The names allowed to be used with the currently selected species */
appropriateNames;
/* Delay rendering of the form until appropriateName has been populated.
* Without this the name dropdown is empty until the species is changed, which
* is rather inconvenient if you want to use the first species in the dropdown */
formReady: boolean = false;
ngOnInit()
{
/* Run the change event handler on page load to populate appropriateNames
* variable and the name dropdown */
this.onChange(this.model.species);
this.formReady = true;
}
/**
* Runs every time the species drop down is changed and populates
* the name dropdown with the names available for that species.
*
* @param species The species currently selected
*/
onChange(species: string) {
console.log('selected species: ', species);
/* Everytime the dropdown changes the name array is iterated through.
* With large arrays this could slow things down, but I haven't had any
* issues with small arrays */
this.appropriateNames= this.names.filter(obj => {
return obj.species === species;
});
/* Change the name dropdown to the first item in the appropriateName array */
this.model.name = this.appropriateNames[0].name;
console.log(this.appropriateNames);
}
}
Link in Ng2-Smart-Table
Ng2-Smart-Table is a great library. Unfortunately, linking inside of a cell is a little difficult. I wanted to use [routerLink] inside the cell, but Angular kept sanitizing it.
To use [routerLink] inside of a cell, create a sub-component.
The table variables look like this:
// Table Stuff
private values = [];
source: LocalDataSource;
settings = {
actions: {
add: false,
edit: false,
delete: false
},
mode: 'external',
columns:
{
tableData: {
title: 'Hostname',
type: 'custom',
renderComponent: LinkComponent
}
}
And to populate the table data:
this.dataService.fetchHosts(key).subscribe((result: object[]) => {
result.map(mapped => {
const value = mapped['value'];
this.values.push({ tableData: value });
});
this.source.load(this.values);
});
The subcomponent, LinkComponent looks like this:
export class HostnameCellComponent implements OnInit{
@Input() value: string;
Pass multiple pieces of data in to a Ng2-Smart-Table sub-component
Okay, but what if your link needs multiple variables to generate it? Unfortunately, the easiest way I found to do this is to create a sub-component as above, concatenate your variables in to a single, comma seperated, string, pass said string in to the component, and split it up there.
This is gross, but it means the table is still sortable.
valuelink.component.ts:
export class HostnameCellComponent implements OnInit{
@Input() value: string;
value_part1: string = '';
value_part2: string = '';
constructor(private route: ActivatedRoute, private router: Router) {
}
ngOnInit()
{
const array: string[] = this.value.split(',');
this.value_part1 = array[0];
this.value_part2 = array[1];
}
}