Nassim
Nassim

Reputation: 2876

change text color of matching text from input in javascript

Here is my code

And I am trying to change the color of any match in the <li> elements that matches the text in the <input> element. So if you type lets say "this is a simple text" the result should look like this:

<input value="this is a simple text" id="term"/> 
<ul id="ul-id" >
    <li id="li-id-1"> hello budy <span style="color:red">this</span> <span style="color:red">is</span> really <span style="color:red">simple</span> stuff </li>
    <li id="li-id-2"> <span style="color:red">this</span> <span style="color:red">is</span> it</li>
    <li id="li-id-3"> there <span style="color:red">is</span> something here</li>
    <li id="li-id-4"> plain <span style="color:red">text</span> file</li>
</ul>

Any help would be appreciated.

Thank you.

Upvotes: 0

Views: 4685

Answers (7)

user1636522
user1636522

Reputation:

You can remove the delay function if you like, but this would lead to a performance loss:

// https://stackoverflow.com/a/9310752/1636522
RegExp.escape = function (text) {
    return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
};

window.addEventListener('load', function () {
    var wrapper = '<span style="background:yellow">$&</span>';
    var input = document.getElementById('term');
    var list = document.getElementById('ul-id');
    var items = list.getElementsByTagName('li');
    var l = items.length;
    var source = Array.prototype.map.call(
        items, function (li) { return li.textContent; }
    );
    var cmp = function (a, b) {
        return b.length - a.length;
    };
    var delay = function (fn, ms) {
        var id, scope, args;
        return function () {
            scope = this;
            args = arguments;
            id && clearTimeout(id);
            id = setTimeout(function () { 
                fn.apply(scope, args); 
            }, ms);
        };
    };
    term.addEventListener('keyup', delay(function () {
        var i, re, val;
        if (val = this.value.match(/[^ ]+/g)) {
            val = val.sort(cmp).map(RegExp.escape);
            re = new RegExp(val.join('|'), 'g');
            for (i = 0; i < l; i++) {
                items[i].innerHTML = source[i].replace(re, wrapper);
            }
        }
        else {
            for (i = 0; i < l; i++) {
                items[i].textContent = source[i];
            }
        }
    }, 500));
});
<input value="" id="term"/> 
<ul id="ul-id" >
    <li id="li-id-1"> hello budy this is really simple stuff </li>
    <li id="li-id-2"> this is it</li>
    <li id="li-id-3"> there is something here</li>
    <li id="li-id-4"> plain text file</li>
</ul>

Similar topic: https://stackoverflow.com/a/20427785/1636522.

Upvotes: 3

Juho
Juho

Reputation: 427

You might do something like this

$('#term').change(function (i) {
    var terms = $('#term').val().split(" ");
    $('#ul-id > li').each(function (i, el) {
        var val = $(el).html().replace(/<[^<]+>/g, ''),
            match;
        terms.forEach(function (term) {
            val = val.replace(new RegExp(term, 'g'),
                '<span style="color:red">' + term + '</span>');
        });
        $(el).html(val);
    });
});

https://jsfiddle.net/1vm0259x/5/

Upvotes: 1

Vigneswaran Marimuthu
Vigneswaran Marimuthu

Reputation: 2532

Plain JS solution

var list = document.querySelector('#ul-id'),
    listItem,
    listItems,
    term = document.querySelector('#term'),
    oldRef = list.innerHTML,
    oldValue;

term.addEventListener('keyup', function () {
    var regExp,
        value = term.value;

    if (oldValue !== value) {
        oldValue = value;
    
        // Reset
        list.innerHTML = oldRef;
    
        if (value.trim() !== '') {
            listItems = list.querySelectorAll('#ul-id li');
            regExp = new RegExp(term.value, 'g');

            // Perform matching
            for (var i = 0; i < listItems.length; i++) {
                listItem = listItems[i];
                listItem.innerHTML = listItem.innerHTML.replace(regExp, function (match) {
                    return '<span class="matched">' + match + '</span>';
                });
            }
        }
    }

}, false);
.matched {
    color: red;
}
<input  id="term"/> 

<ul id="ul-id" >

    <li id="li-id-1"> hello budy this is really simple stuff </li>
    <li id="li-id-2"> this is it</li>
    <li id="li-id-3"> there is something here</li>
    <li id="li-id-4"> plain text file</li>

</ul>

Upvotes: 1

Ashok Rathod
Ashok Rathod

Reputation: 840

you can handle blur event or you can copy paste the inner function code to wherever it is required. this is the guide code here you can more explore match function as per your requirement and then can traverse your li elements as shown below.

$('#term).blur(function() {

  $('#ul-id li').foreach(function()
  {
   if($(this).text().match($("#term").text()))
   {
     ///set/change here  color of  li element
      $(this).css('color', 'red');
   }
  }
}

Upvotes: 0

Arun P Johny
Arun P Johny

Reputation: 388326

With jQuery

if (!RegExp.escape) {
  RegExp.escape = function(value) {
    return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&")
  };
}

$('#term').on('change keyup', function() {
  //$('#ul-id li .highlight').contents().unwrap();//remove previous highlights

  var parts = this.value.split(' ').map(function(value) {
    return '\\b' + RegExp.escape(value) + '\\b';
  });
  var regex = new RegExp(parts.join('|'), 'g');

  $('#ul-id li ').each(function() {
    var text = $(this).text();
    $(this).html(text.replace(regex, function(part) {
      return '<span class="highlight">' + part + '</span>'
    }))
  })
});
.highlight {
  color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input id="term" />
<ul id="ul-id">
  <li id="li-id-1">hello budy this is really simple stuff</li>
  <li id="li-id-2">this is it</li>
  <li id="li-id-3">there is something here</li>
  <li id="li-id-4">plain text file</li>
</ul>

Upvotes: 0

Arun P Johny
Arun P Johny

Reputation: 388326

You can use the below solution if there is no html contents in the li elemnets

if (!RegExp.escape) {
  RegExp.escape = function(value) {
    return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&")
  };
}

var lis = [].slice.call(document.querySelectorAll('#ul-id li'));
lis.forEach(function(el) {
  el.dataset.text = el.innerHTML;
});

document.querySelector('#term').addEventListener('change', function() {
  var parts = this.value.split(' ').map(function(value) {
    return '\\b' + RegExp.escape(value) + '\\b';
  });
  var regex = new RegExp(parts.join('|'), 'g');

  lis.forEach(function(el) {
    el.innerHTML = el.dataset.text.replace(regex, function(part) {
      return '<span class="highlight">' + part + '</span>'
    })
  });
});
.highlight {
  color: red;
}
<input id="term" />
<ul id="ul-id">
  <li id="li-id-1">hello budy this is really simple stuff</li>
  <li id="li-id-2">this is it</li>
  <li id="li-id-3">there is something here</li>
  <li id="li-id-4">plain text file</li>
</ul>

Upvotes: 0

Wa Kai
Wa Kai

Reputation: 466

I don't know if it is possible with only RegEx, but here is a jQuery solution:

$('#term').change(function() {
    var inpArr = $(this).val().split(" ");

    $('#ul-id li').each(function() {
        var liArr = $(this).text().split(" ");
        var txt = "";
        $.each(liArr, function(i, v) {
            if(inpArr.indexOf(v) > -1) {
                txt += "<span class='red'>"+ v +"</span> ";
            } else {
                txt += v + " ";
            }
        });
        $(this).html(txt);
    });
});

span.red {
     color: red; 
}

And the working fiddle: https://jsfiddle.net/ermk32yc/1/

Upvotes: 1

Related Questions