
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
@softeq/angular-route-data
Advanced tools
@softeq/angular-route-data allows to keep URL up to date with the page content.
Let's consider the following example to understand what problem this library tries to solve.
Imagine we have a page under the route /heroes displaying list of heroes and toggle that allows to show only active heroes.

When user turns switch on we need to show only active heroes and update URL to /heroes?onlyActive=true. In addition user can open this URL by putting it into the address bar of the browser and go to the same page having switch show only active heroes on.
In the real world, page can have more criteria, like name of hero, set of checkboxes, etc.
Such behavior allows user to keep bookmarkable URLs or send URLs via messenger. For developer it can simplify implementation of back behavior (when user press on browser back button).
The following code demonstrates behavior described in Motivation section.
interface Hero {
name: string;
active: boolean;
}
@Component({
selector: 'hero-list',
template: `
<mat-slide-toggle [formControl]="onlyActiveControl">Show only active heroes</mat-slide-toggle>
<mat-list>
<mat-list-item *ngFor="let hero of filteredHeroes">{{ hero.name }}</mat-list-item>
</mat-list>
`,
})
export class HeroListComponent implements OnInit {
onlyActiveControl = new FormControl(false);
heroes: Hero[] = [
{ name: 'Black Widow', active: false },
{ name: 'Groot', active: true },
{ name: 'Hulk', active: true },
{ name: 'Iron Man', active: false },
{ name: 'Rocket Raccoon', active: true },
{ name: 'Thor', active: true },
];
filteredHeroes: Hero[];
constructor(private route: ActivatedRoute,
private routeData: RouteDataService) {
}
ngOnInit(): void {
const tracker = this.routeData.tracker(controlTracker('onlyActive', this.onlyActiveControl, booleanMapper()));
tracker.listen(this.route);
tracker.filterChanges.subscribe(([onlyActive]) => {
this.filteredHeroes = onlyActive ? this.heroes.filter((hero) => hero.active) : this.heroes;
});
}
}
Here we track value of onlyActiveControl and URL of the current page.
If user switches value of control, URL and set of filteredHeroes are updated correspondingly.
From the other side when user opens page by /heroes?onlyActive=true URL, onlyActiveControl is already set to true and list of heroes shows only active heroes.
Let's consider this code in more details.
All tracking logic is provided by RouteDataService. Also we need ActivatedRoute from @angular/router package to track route parameters
constructor(private route: ActivatedRoute,
private routeData: RouteDataService)
Create instance of RouteTracker. RouteTracker is a key entity for tracking behavior. It can be created using RouteDataService.tracker method.
const tracker = this.routeData.tracker(controlTracker('onlyActive', this.onlyActiveControl, booleanMapper()));
tracker method accepts set of RouteParamTracker.
RouteParamTracker tracks subset of route query parameters. It is responsible for
In our example the following code create RouteParamTracker
controlTracker('onlyActive', this.onlyActiveControl, booleanMapper())
which tracks value of onlyActive query parameter, mirrors its value in the instance of FormControl (onlyActiveControl) and treats this value as boolean (using booleanMapper(). It is important to map query parameter value, because query parameter is always a string).
This way RouteParamTracker created by controlTracker
onlyActive query parameter into the onlyActiveControlonlyActiveControl when user toggles switchonlyActive query parameter when user toggles switchBind route to the instance of RouteTracker
tracker.listen(this.route);
This way RouteTracker can listen for changes in route query parameters.
Update displayed data when filter is changed
tracker.filterChanges.subscribe(([onlyActive]) => {
this.filteredHeroes = onlyActive ? this.heroes.filter((hero) => hero.active) : this.heroes;
});
filterChanges emits new value as soon as one of assigned RouteParamTrackers notifies about changes.
What if value of onlyActiveControl from the Example section should be set to true by default.
This way when user opens the page by URL /heroes, he should see switch Show only active heroes in toggled state. When user clicks on switch, URL become /heroes?onlyActive=false. One more click makes URL /heroes?onlyActive=true and shows only active heroes again.
There is no big sense to set onlyActive=true when true is a default value. From the perspective of page content URLs /heroes and /heroes?onlyActive=true are the same.
In order to hide query parameter when it accepts default value, you can tell RouteParamTracker what value is a default one.
const tracker = this.routeData
.tracker(controlTracker('onlyActive', this.onlyActiveControl, booleanMapper()).withDefault(true));
RouteParamTracker can be registered as filter or effect. Example of filter RouteParamTracker was shown in the Example section. Effect RouteParamTracker is used when you need to avoid dramatic changes in UI.
Look at the following snippet.
Say, you need to track scroll position and save it in the URL like /heroes?onlyActive=true&scroll=150. This allows to open page on the same scroll position it had before.
const tracker = this.routeData.tracker(
controlTracker('onlyActive', this.onlyActiveControl, booleanMapper()),
scrollTracker(...)); // this is just an example, library does not provide such tracker
tracker.listen(this.route);
tracker.filterChanges.subscribe(([onlyActive]) => {
// filter set of heroes
});
Here, scrollTracker is registered as filter. It means each time scroll position is changed filterChanges will trigger new filter and set of filteredHeroes will be recalculated. This is barely expected behavior. We need the way to track scroll position, but should not emit new filter. To implement such behavior we can register scrollTracker as effect.
const tracker = this.routeData
.tracker(controlTracker('onlyActive', this.onlyActiveControl, booleanMapper()))
.withEffects(scrollTracker(...));
tracker.listen(this.route);
tracker.filterChanges.subscribe(([onlyActive]) => {
// filter set of heroes
});
Now scroll position will be tracked, but this will not lead to emitting of new filter.
RouteParamTrackersRouteParamTracker factory | Note |
|---|---|
controlTracker | Creates tracker that mirrors value of single query parameter in the provided AbstractControl |
filterTracker | Creates tracker that mirrors value of single query parameter in the instance of Filterable object |
manualTracker | Creates the simplest tracker that allows to track value manually and mirror it in the single query parameter |
observableFilterTracker | Creates tracker that mirrors values of provided stream in the single query parameter |
observablePlainFilterTracker | Creates tracker that mirrors values of provided stream in the set of query parameters |
FAQs
Allows to keep URL up to date with the page content
We found that @softeq/angular-route-data demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.