I am using an ion-searchbar
to filter an ion-list
containing ion-item-sliding
elements. I would like to create a pipe that highlights the search query so the user has instantaneous feedback about what part of their query was matched. For example, if my list contains an item “Word” and I search for “W” the pipe will reformat the list item to contain <span class="highlighted">W</span>ord
.
I’m not sure if this is the best way to accomplish this but the code that I’m using for the pipe and its page are below. It feels a little hacky but I had to use <span [innerHTML]="word | highlight:letter"></span>
in the page otherwise the pipe returns escaped HTML. I understand this is a security concern but I’m going to scrub the user input before it hits the pipe.
This all seems to work well except one small issue. When you click/press on the text inside the span tag the click event fires but the touch animation is not shown (ripple or highlight effect). The touch animation is shown if you press anywhere outside of the contents of the span tag – but still in the button of course. This only happens with I use the [innerHTML] property. Even if I remove the pipe and just set [innerHTML]="word"
I still observe the same behavior. If I just put plain text inside of a span tag everything works as expected.
I tested this natively on iOS and android. Not sure if it is a bug with angular or if it is an ionic problem or I’m just doing something wrong?
Cordova CLI: 6.0.0
Ionic Version: 2.0.0-beta.1
Ionic CLI Version: 2.0.0-beta.17
Ionic App Lib Version: 2.0.0-beta.8
OS:
Node Version: v5.2.0
highlight.pipe.js
import {Pipe, PipeTransform} from 'angular2/core';
@Pipe({
name: 'highlight'
})
export class HighlightPipe implements PipeTransform {
/**
* Highlight a string within a string by adding <span class="highlighted"> around the value
*
* Usage:
* <span [innerHTML]="word | highlight:letter"></span>
* Example:
* <span [innerHTML]="word | highlight:w"></span>
* Formats to: <span><span class="highlighted">w</span>ord</span>
* @param value
* @param args
* @returns {*}
*/
transform(value, args) {
var string = args[0];
if(string.length > 0) {
var regexp = new RegExp('(' + string + ')', 'gi');
return value.replace(regexp, '<span class="highlighted">$1</span>');
} else {
return value;
}
}
}
somepage.html
<ion-toolbar>
<ion-searchbar primary
placeholder="Search"
[(ngModel)]="query"
(input)="filterItems()"
hideCancelButton=true>
</ion-searchbar>
</ion-toolbar>
<ion-content>
<ion-list>
<ion-item-sliding *ngFor="#item of items">
<button ion-item (click)="selectItem(item.name)">
<ion-thumbnail item-left>
<img src="images/{{item.name}}.svg">
</ion-thumbnail>
<h2><span [innerHTML]="item.name | highlight:query"></span></h2>
</button>
</ion-item-sliding>
</ion-list>
</ion-content>