#javascript #angular
#javascript #angular
Вопрос:
Я пытаюсь создать функцию «search next», в которой после того, как пользователь нажмет enter, будет вызвана функция, которая фокусируется на следующем совпадении. Сложность заключается в том, что текст для поиска представляет собой контейнер div с вложенными элементами, каждый со своим индивидуальным текстом. Я могу создать выделение с помощью каналов, но не уверен, как перейти к следующему тексту, который соответствует поисковому запросу. Есть идеи?
Вот канал выделения:
@Pipe({
name: 'highlight'
})
export class HighlightPipe implements PipeTransform {
transform(value: string, args: string): any {
if (args amp;amp; value) {
value = String(value); // make sure its a string;
const startIndex = value.toLowerCase().indexOf(args.toLowerCase());
if (startIndex != -1) {
console.log(startIndex);
const endLength = args.length;
const matchingString = value.substr(startIndex, endLength);
return value.replace(matchingString, "<mark>" matchingString "</mark>");
}
}
return value;
}
}
Шаблон с поисковым вводом и контейнером div, который содержит весь текст:
<section *ngFor="let section of country.Section">
<div class="main" [innerHTML]="section.Name | highlight: searchTerm"></div>
<div *ngFor="let sectionParagraph of section.SectionParagraph">
<p class="paragraph" [innerHTML]="sectionParagraph.ParagraphText | highlight: searchTerm"></p>
<p class="paragraph" [innerHTML]="sectionParagraph.ChildParagraphs | highlight: searchTerm"></p>
</div>
<div *ngFor="let subsection of section.SubSection">
<div class="secondary" [innerHTML]="subsection.Name | highlight: searchTerm"></div>
<div *ngFor="let subSubsectionParagraph of subsection.SubSectionParagraph">
<p class="paragraph" [innerHTML]="subSubsectionParagraph.ParagraphText | highlight: searchTerm"></p>
<div *ngFor="let childParagraph of subSubsectionParagraph.ChildParagraphs">
<p class="paragraph" [innerHTML]="childParagraph.ParagraphText | highlight: searchTerm"></p>
</div>
</div>
</div>
<hr>
</section>
И поисковый ввод по тому же шаблону:
<mat-form-field class="example-full-width" style="margin-left: 120px">
<input matInput placeholder="Search Text" [value]="searchTerm" [(ngModel)]="searchTerm" (input)="highlight($event)" (keyup.enter)="nextTerm()">
</mat-form-field>
Редактировать: я бы хотел избежать использования какого-либо jQuery для решения
Ответ №1:
Идея заключается в том, чтобы использовать канал с двумя аргументами «search» и «index», затем вам нужно изменить канал, чтобы учесть эти изменения
transform(value: string, args: string,index:number=-1): any {
if (args amp;amp; value) {
value = String(value); // make sure its a string;
const startIndex = value.toLowerCase().indexOf(args.toLowerCase(),index);
if (startIndex != -1) {
console.log(startIndex);
const endLength = args.length;
const matchingString = value.substr(startIndex, endLength);
return value.substring(0,startIndex) "<mark>" matchingString "</mark>" value.substring(startIndex endLength);
}
}
return value;
}
Затем вы вызываете канал, подобный тому, который я сделал с помощью < p> , но важно то, как передаются два аргумента
<p (click)="click()" class="paragraph"
[innerHTML]="text | highlight: search:index"></p>
Функция click() похожа на:
//This are the variables I used in a more simple example
index:number=0;
text='Hola mundo, Hola Mundo';
search="Hola";
click()
{
let index=this.text.indexOf(this.search,this.index 1);
this.index=index>0?index:0;
}
Вы можете быть примером в stackblitz
Обновление Если у нас есть последовательность текста, полезно, чтобы наш текст стал объектом с индексом
sections = [
{ text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', index: 0 },
{ text: 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.', index: 1 },
{ text: 'Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', index: 2 },
{ text: 'Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. ', index: 3 }
]
Тогда наш канал может учитывать «индекс»
//the .html
<div *ngFor="let section of sections;let i=index">
<p class="paragraph" [innerHTML]="section.text | highlight: search:index:(active==section.index)"></p>
</div>
<button (click)="click()">next</button>
//the pipe
//we get "active"
transform(value: string, args: string,index:number=-1,active:boolean): any {
//if active=false not do anything
if (args amp;amp; value amp;amp; active) {
value = String(value); // make sure its a string;
const startIndex = value.toLowerCase().indexOf(args.toLowerCase(),index);
if (startIndex != -1) {
const endLength = args.length;
const matchingString = value.substr(startIndex, endLength);
return value.substring(0,startIndex) "<mark>" matchingString "</mark>" value.substring(startIndex endLength);
}
}
return value;
}
что ж, функция «щелчок» немного сложнее
click() {
let index = -1;
if (this.active < 0) {
this.active = 0;
index = this.sections[this.active].text.indexOf(this.search);
}
else {
if (this.index < 0) {
index = this.sections[this.active].text.indexOf(this.search);
index = this.sections[this.active].text.indexOf(this.search, index 1);
}
else
index = index = this.sections[this.active].text.indexOf(this.search, this.index 1);
}
if (index < 0)
{
let count=0;
this.active = (this.active 1) % this.sections.length;
while (this.sections[this.active].text.indexOf(this.search)<0
amp;amp; count<this.sections.length)
{
this.active = (this.active 1) % this.sections.length;
count ;
}
}
this.index = index;
}
В вашем случае вам нужно вычислить «индекс» раздела и подраздела, чтобы сделать их последовательными.
Комментарии:
1. спасибо за это, но мой сценарий включает вложенный объект, который включает в себя несколько каналов. В вашем примере индекс основан на тексте, привязанном только к одному элементу. У меня есть несколько элементов, которые мне нужны, чтобы иметь возможность перейти к следующему индексу (см. Шаблон html)
2. В вашем случае вы можете добавить новый параметр «active» в свой канал (становится true или false) и активную переменную в вашем .ts. функция (щелчок) становится более сложной. Я оставил в stackblitz.com/edit /… пример «как есть». Я надеюсь, что это поможет вам