Organization of search in a web page in JavaScript (without jQuery)

A couple of days ago I received a test task from the company for the job Front-end dev. Of course, the task consisted of several points. But now it will be only one of them - the organization of the search on the page. Those. a banal search for the text entered in the field (analogue of Ctrl + F in the browser). The peculiarity of the task was that the use of any JS frameworks or libraries is prohibited. All write in native native javascript .

(For clarity, I will continue to accompany the entire article with screenshots and code, so that I and you can understand what this is about at a particular moment)

Search for a ready solution


My first thought: someone already wrote exactly this, you need to google and copy-paste. So I did. In an hour I found two quite good scripts which as a matter of fact worked equally, but were written differently. I chose the one in the code of which I figured out better and inserted it into my starnichka.

If anyone is interested, I took the code here .

The script immediately earned. I thought that the issue had been resolved, but as it turned out, there was no offense to the author of the script, there was a huge flaw in it. The script conducted a search on the entire contents of the tag ...and, as you probably already guessed, when searching for any combination of characters that resemble a tag or its attributes, the entire HTML page was broken.

Why did the script work incorrectly?


It's simple. The script works as follows. First, we write the entire contents of the body tag to the variable , then we look for matches with the regular expression (the user sets it when entering the text field) and then replace all matches with the following code:

<spanstyle="background-color: yellow;">...найденное совпадение...</span>

And then we replace the current body tag with the new one received. The markup is updated, the styles change and all the found results are highlighted in yellow on the screen.

You have probably already understood what the problem is, but I will nevertheless explain in more detail. Imagine that you entered the word "div" in the search field . As you understand, inside the body there are many other tags, including the div . And if we all apply the styles mentioned above to the “div” , then it will no longer be a block, but an incomprehensible thing, since the construction breaks down. In the end, after rewriting the markup, we get a completely broken web page. It looks like this.

It was before the search: To see it completely It became after the search:put the photo on the Internet
upload photos for freeFully lookout

As you can see, the page breaks down completely. In short, the script turned out to be inoperative, and I decided to write my own from scratch, which is what this article is about.

So we write the script from scratch


How it all looks.



Now we are interested in the form with the search. Circled it in red.

Let's see a little. I implemented it as follows (for now pure HTML). Form with three tags.

The first is for entering text;
The second is to cancel the search (deselect);
The third one is for search (select the found results).

<form><inputtype="text"value=""placeholder="Search"autofocus><inputtype="button"value=" "title="Отменить поиск"><inputtype="submit"value=" "title="Начать поиск"></form>

So, we have a field for input and 2 buttons. JavaScript will be writing in the js.js file Suppose that you have already created and connected it.

The first thing we will do is: assign the function calls when clicking on the search button and the cancel button. It will look like this:

<form><inputclass="place_for_search"type="text"id="text-to-find"value=""placeholder="Search"autofocus><inputclass="button_for_turn_back"type="button"onclick="javascript: FindOnPage('text-to-find',false); return false;"value=" "title="Отменить поиск"><inputclass="button_for_search"type="submit"onclick="javascript: FindOnPage('text-to-find',true); return false;"value=" "title="Начать поиск"></form>

Let's explain a little what's there and why.

The text field is given id = “text-to-find” ( by this id we will refer to the element from js ).

The cancel button gives the following attributes: type = "button" onclick = "javascript: FindOnPage ('text-to-find', false); return false; "

- Type: button
- When pressed, the function FindOnPage ('text-to-find', false) is called; and passes the id of the field with the text, false

To the search button, we give the following attributes: type = "button" onclick = "javascript: FindOnPage ('text-to-find', true); return false; "

- Type: submit (not a button because here you can use Enter after typing in the field, and you can also use button)
-When pressed, the function FindOnPage ('text-to-find', true) is called; and passes the id of the field with the text, true

You probably noticed another 1 attribute: true / false . We will use it to determine which button was pressed (cancel the search or start the search). If we click on cancellation, then we pass false . If we click on the search, then we pass true .

Okay, move on. Go to javascript

We assume that you have already created and connected the js file to the DOM.

Before we start writing code, let's digress and first discuss how things should work. Those. essentially write a plan of action. So, we need so that when entering text in the field, we search through the page, but we cannot touch tags and attributes. Those. only text objects. How to achieve this - sure there are many ways. But now we will use regular expressions.

So, the following regular expression will only search for text next. of the form: "> ... text ... <". Those. will search only text objects, while tags and attributes will remain intact.

/>(.*?)</g

So we will find the necessary parts of the code that we will parse and look for matches with the text that the user entered. Then we will add styles to the found objects and then replace the html code with a new one.

Let's get started First, the variables that we need.

var input,search,pr,result,result_arr, locale_HTML, result_store;
//input - принимаем текст, который ввел пользователь//search - делаем из строки регулярное выражение//pr - сохраняем в нее текущий <body></body>//result - выборка текста из pr (т.е. отсекаем теги и атрибуты)//result_arr - аналог pr, но со стилями для подсветки//locale_HTML - оригинал <body></body> который менять не будем, используем для обнуления стилей

And immediately determine the locale_HTML value regardless of whether we are looking for something or not. This is necessary to immediately keep the original page and have the opportunity to reset the styles.

var input,search,pr,result,result_arr, locale_HTML, result_store;
locale_HTML = document.body.innerHTML;   // сохраняем в переменную весь body (Исходный)

Ok, now it's worth creating a function that is called from the DOM . Immediately let's estimate that inside we should have 2 functions, each of which works depending on the button pressed. After all, we either conduct a search or reset it. And this is controlled by the attribute true / false , as you remember. You also need to understand that when you re-search the old styles should be reset. So we get the following:

var input,search,pr,result,result_arr, locale_HTML, result_store;
locale_HTML = document.body.innerHTML;   // сохраняем в переменную весь body (Исходный)functionFindOnPage(name, status) {
        if(status) { FindOnPageBack(); FindOnPageGo(); } //чистим прошлое и Выделяем найденноеif(!status) { FindOnPageBack(); } //Снимаем выделение
}

Ok, some of the logic is implemented, move on. It is necessary to check the received word for the number of characters. After all, why do we need to look for 1 letter / symbol. In general, I decided to limit this possibility to 3+ characters.

So, first we accept the value that the user has entered, and, depending on its length, we perform either the main search function, or the function of displaying warnings and zeroing. It will look like this:

var input,search,pr,result,result_arr, locale_HTML, result_store;
locale_HTML = document.body.innerHTML;   // сохраняем в переменную весь body (Исходный)functionFindOnPage(name, status) {
	input = document.getElementById(name).value; //получаем значение из поля в htmlif(input.length<3&&status==true) {
		alert('Для поиска вы должны ввести три или более символов');
		functionFindOnPageBack() { document.body.innerHTML = locale_HTML; }   //обнуляем стили
	}
        if(input.length>=3)
	{
              //выполняем поиск
        }
        functionFindOnPageBack() { document.body.innerHTML = locale_HTML; }   //обнуляем стилиif(status) { FindOnPageBack(); FindOnPageGo(); } //чистим прошлое и Выделяем найденноеif(!status) { FindOnPageBack(); } //Снимаем выделение
}

Now I will explain this section of the code. The only thing that could become unclear is this line:

function FindOnPageBack () {document.body.innerHTML = locale_HTML; }

Everything is simple: the innerHTML method returns the html object code. In this case, we simply replace the current body with the original body , which we saved when loading the entire page.

Moving on. Give the values ​​of the main variables.

var input,search,pr,result,result_arr, locale_HTML, result_store;
locale_HTML = document.body.innerHTML;   // сохраняем в переменную весь body (Исходный)functionFindOnPage(name, status) {
	input = document.getElementById(name).value; //получаем значение из поля в htmlif(input.length<3&&status==true) {
		alert('Для поиска вы должны ввести три или более символов');
		functionFindOnPageBack() { document.body.innerHTML = locale_HTML; }   //обнуляем стили
	}
        if(input.length>=3)
	{
              functionFindOnPageGo() {
                     search = '/'+input+'/g';  //делаем из строки регуярное выражение
		     pr = document.body.innerHTML;   // сохраняем в переменную весь body
		     result = pr.match(/>(.*?)</g);  //отсекаем все теги и получаем только текст
		     result_arr = [];   //в этом массиве будем хранить результат работы (подсветку)
              }
        }
        functionFindOnPageBack() { document.body.innerHTML = locale_HTML; }   //обнуляем стилиif(status) { FindOnPageBack(); FindOnPageGo(); } //чистим прошлое и Выделяем найденноеif(!status) { FindOnPageBack(); } //Снимаем выделение
}

So, at this stage, we already have the main variables and values. Now you need to give the necessary parts of the code styles with the selected background. Those. checking the selected text for a regular expression (in fact, we selected the text with a regular expression again by parsing the regular expression). To do this, you need to make a regular expression from the entered text (done), and then execute the method passed in the form of a text. Here the eval () method will help us .

In general, after we replace the text and get the result with the styles, we need to replace the current html with the received one. We do.

var input,search,pr,result,result_arr, locale_HTML, result_store;
locale_HTML = document.body.innerHTML;   // сохраняем в переменную весь body (Исходный)functionFindOnPage(name, status) {
	input = document.getElementById(name).value; //получаем значение из поля в htmlif(input.length<3&&status==true) {
		alert('Для поиска вы должны ввести три или более символов');
		functionFindOnPageBack() { document.body.innerHTML = locale_HTML; }   //обнуляем стили
	}
        if(input.length>=3)
	{
              functionFindOnPageGo() {
                     search = '/'+input+'/g';  //делаем из строки регуярное выражение
		     pr = document.body.innerHTML;   // сохраняем в переменную весь body
		     result = pr.match(/>(.*?)</g);  //отсекаем все теги и получаем только текст
		     result_arr = [];   //в этом массиве будем хранить результат работы (подсветку)for(var i=0; i<result.length;i++) {
		        result_arr[i] = result[i].replace(eval(search), '<span style="background-color:yellow;">'+input+'</span>'); //находим нужные элементы, задаем стиль и сохраняем в новый массив
			}
		     for(var i=0; i<result.length;i++) {
			pr=pr.replace(result[i],result_arr[i])  //заменяем в переменной с html текст на новый из новогом ассива
			}
		     document.body.innerHTML = pr;  //заменяем html код
              }
        }
        functionFindOnPageBack() { document.body.innerHTML = locale_HTML; }   //обнуляем стилиif(status) { FindOnPageBack(); FindOnPageGo(); } //чистим прошлое и Выделяем найденноеif(!status) { FindOnPageBack(); } //Снимаем выделение
}

In fact, everything is ready, and the script is already running. But add a couple of details for beauty.

1) Cut the spaces of the text that the user enters. Paste this code:

        input = numer.replace(/^\s+/g,'');
        input = numer.replace(/[ ]{1,}/g,' ');

After this line:

        input = document.getElementById(name).value; //получаем значение из поля в html

2) Let's make a check for matches (if no matches were found, let us know). We insert this code inside the function FindOnPageGo () after the variables.

var warning = true;
	for(var i=0;i<result.length;i++) {
	if(result[i].match(eval(search))!=null) {
			warning = false;
		}
	}
	if(warning == true) {
		alert('Не найдено ни одного совпадения');
	}

View the source here .
Download the source here .

That's it. Of course, you can add a scroll to the first result found, live ajax search, and in general you can improve endlessly. Now this is a fairly primitive search site. The purpose of the article was to help beginners, if there is the same question as mine. After all, I did not find a simple ready-made solution.

PS: for correct work it is necessary to remove text hyphenation in the html document in those places where there is plain text between the tags.

For example, instead of

<p> бла бла бла
  </p>

Need to
<p> бла бла бла </p>

It doesn’t matter, you can get rid of these transfers automatically on the service, but you can tell me at the same time how to fix this if you understand me before.

Also, if someone wrote similar, but with a live search, share the source, it will be interesting to make out.

I will be glad to hear constructive criticism, opinions, maybe recommendations.

The other day I added a little code, made a live search on the page. So, that question is removed. HTML code has not changed. JS can look here .

Search is conducted on tags with the class "place_for_live_search". So in order to parsil algorithm the desired content, add a class and ready.


Also popular now: