Let's detail the steps to create a custom pipe in a JHipster 6.10.5 application with angular 10.0.0.

We will define a pipe that converts a string into a kebab-case to use the value of an attribute of an entity on a link that requires kebab-case, and that we will use on a routerLink to achieve routes dynamically from values of treated entities in each HTML template.

By respecting the structure of the JHipster application we first create in the path /src/main/webapp/app/shared/ a folder 'pipes' and within them we create the file kebab-case-pipe.ts with the following typescript code:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'kebabCasePipe'
})
export class KebabCasePipe implements PipeTransform {

  transform(value: any, ...args: any[]): any {
    if (typeof value === 'string') {
      return value.toLowerCase().split(' ').join('-');
    }
    return null;
  }
}

We declare the pipe in the module.ts file of the group to which it belongs, in this case in a file named new-issue.module.ts, importing the pipe and adding it in 'declarations' and 'providers':

import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';

import { LabFrontWebAppmonolithicClient01GeneralSharedModule } from 'app/shared/shared.module';
import { NewIssueComponent } from './new-issue.component';
import { NewIssueUpdateComponent } from './new-issue-update.component';
import { NewIssueSeeTasksComponent } from './new-issue-see-tasks.component';
import { NewIssueSeeTasksPipeBrokenIsThereInsuranceComponent } from './new-issue-see-tasks-pipe-broken-is-there-insurance.component';
import { newIssueRoute } from './new-issue.route';

import { KebabCasePipe } from 'app/shared/pipes/kebab-case-pipe';

@NgModule({
  imports: [LabFrontWebAppmonolithicClient01GeneralSharedModule, RouterModule.forChild(newIssueRoute)],
  declarations: [
    NewIssueComponent,
    NewIssueUpdateComponent,
    NewIssueSeeTasksComponent,
    NewIssueSeeTasksPipeBrokenIsThereInsuranceComponent,
    KebabCasePipe,
  ],
  providers: [KebabCasePipe],
})
export class LabFrontWebAppmonolithicClient01GeneralNewIssueModule {}

As this above statement we already have available the KebabCasePipe for use in HTML templates using the pipe | within the processing of the component's public properties between double curly braces: {{ }}.

And in the component of the page where the pipe will be used in the HTML template should be imported and added in the constructor:

...
import { KebabCasePipe } from 'app/shared/pipes/kebab-case-pipe';
...
@Component({
  selector: 'jhi-new-issue-see-tasks',
  templateUrl: './new-issue-see-tasks.component.html',
})
export class NewIssueSeeTasksComponent implements OnInit, OnDestroy {
...
constructor(
  protected activatedRoute: ActivatedRoute, 
  protected aPIjBPMClientService: APIjBPMClientService, 
  private fb: FormBuilder, 
  public kebabCasePipe: KebabCasePipe) {}
...
}

And with this declaration, which is not necessary if we only use the pipe in HTML templates, we will be able to use the template in the component where it has been imported and injected into the builder. Its use in this component, or for example in a service if injected into a service, is used by calling the 'transform' method of the injected KebabCase object instance.

In the HTML template we use it as follows:

{{ entryTask['task-name'] | kebabCasePipe }}

This code does is transform the value of an entity named entryTask['task-name'] which has for example 'Ticket is there insurance' listed in HTML template as 'ticket-is-there-insurance'.

But in our case, we have in the 'routes' file routes specified by task-name we need that on the [routerLink] button of an HTML template use the pipe to mount the URL correctly. In this case the pipe call should be made as it would be made within a typescript code using the 'transform' method of the pipe instance of the component that was injected into the constructor:

<button type="submit" 
[routerLink]="['/new-issue/task/claim-and-work', entryTask['task-container-id'], entryTask['task-proc-def-id'], entryTask['task-id'], 'task-human',  kebabCasePipe.transform(entryTask['task-name']), 'edit']" 
class="btn btn-info btn-sm" 
[disabled]="(entryTask['task-status'] != 'Completed')? false:true">
  <fa-icon icon="user-cog"></fa-icon>
  <span class="d-none d-md-inline" jhiTranslate="new-issue-see-tasks.keypad.claim-and-work">Claim and work</span>
</button>

This 'button' for example for a form named 'Ticket is there insurance' of a human task in a BPM process named 'pipe-broken-project.pipe-broken' of an execution container on an KIE Server jBPM server, to which this app is integrated through the REST API of this server, named 'pipe-broken-project_1.0.3-SNAPSHOT' mounts the following 'route' dynamically:

/new-issue/task/claim-and-work/pipe-broken-project_1.0.3-SNAPSHOT/pipe-broken-project.pipe-broken/222/task-human/ticket-is-there-insurance/edit

In this way in the path file of this module of the application we can manage in routing to each HTML template of each existing form, using the name of each form we receive from the KIE Server jBPM server as the route name being unique, but requiring to be in kebab-case.