0

Firstly, I must apologize if the title is poorly constructed. I'm struggling to try to consolidate all the valid points into a brief enough title. If you can think of a better alternative, please feel free to edit.

The Problem

I've created a JavaScript/jQuery alternative to the poorly supported <datalist> HTML5 element and for the most part I'm happy with how it has turned out.

It all works, but one problem I have with special RegExp characters, is that I'm not too sure how I can escape them so that I'm not being given errors in the console.

Characters in particular that I want to escape are (, ) and /. I know that in JavaScript regular expressions, you should use a backslash to escape these characters, but of the attempts I've tried thus far, the code stops working completely so clearly I'm not doing something right.

I am just wondering how I could implement the escaping into my current code? You can see from the commented-out lines some other methods I've tried.

The Error

The input works and displays the games correctly. However, if you select one of the Grand Theft Auto V options from the jsFiddle and then go to backspace on the parentheses, the console will throw this error:

Uncaught SyntaxError: Invalid regular expression: /Grand Theft Auto V (PC/: Unterminated group

The Code

Live preview: jsFiddle

JavaScript/jQuery:

$('#game-name').keyup( function() {
    var input     = $('#game-search');
    var offset    = input.offset();
    var game_name = $("#game-search").val();

    // List
    function show() {
        $('#game-list').css({
            'display': 'inline-block',
            'left': offset.left,
            'min-width': input.outerWidth(),
            'top': offset.top + input.outerHeight()
        });
    }
    function hide() {
        $('#game-list').css({
            'display': 'none',
            'left': offset.left,
            'min-width': input.outerWidth(),
            'top': offset.top + input.outerHeight()
        });
    }
    if (game_name.length >= 1) {
        show();
    }
    else {
        hide();
    }

    // Filter
    var regexp = new RegExp( game_name, "i" );
    //var regexp = new RegExp(/[A-Za-z0-9_()\/]/, "i");
    // [A-Za-z0-9_()\/]
    $("#game-list ul").children("li").each(function(index) {
        if (game_name.length < 1) {
            $(this).addClass('reset').removeClass('match no-match');
        }
        else {
            //if (/[A-Za-z0-9_()\/]/i.test( $(this).html() )) {
            if (regexp.test( $(this).html() )) {
                $(this).addClass('match').removeClass('no-match reset');
            } else {
                $(this).addClass('no-match').removeClass('match reset');
            }
        }
    });

    // Apply
    $('#game-list ul li').click( function() {
        $('#game-search').val( $(this).attr('value') );
        $('#game-list').css('display', 'none');
    });
});

HTML:

<input type="text" id="game-search">

<div id="game-list">
    <ul>
        <li class="" value="BeamNG.drive" data-series="BeamNG.drive">BeamNG.drive</li>
        <li class="" value="Crash Bandicoot: N. Sane Trilogy" data-series="Crash Bandicoot">Crash Bandicoot: N. Sane Trilogy</li>
        <li class="" value="Grand Theft Auto V (PC)" data-series="Grand Theft Auto">Grand Theft Auto V (PC)</li>
        <li class="" value="Grand Theft Auto V (PS3/PS4)" data-series="Grand Theft Auto">Grand Theft Auto V (PS3/PS4)</li>
        <li class="" value="Grand Theft Auto V (X360/XBO)" data-series="Grand Theft Auto">Grand Theft Auto V (X360/XBO)</li>
        <li class="" value="Project CARS" data-series="Project CARS">Project CARS</li>
        <li class="" value="Project CARS 2" data-series="Project CARS">Project CARS 2</li>
        <li class="" value="Subnautica" data-series="Subnautica">Subnautica</li>
    </ul>
</div>

Thank you.

DylRicho
  • 895
  • 1
  • 10
  • 25
  • Why _"poorly supported"_? Only Safari doesn't support ``: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/datalist#Specifications – Andreas Jul 02 '18 at 06:04
  • @Andreas; because for my intended usage, it needs to be universally available. That includes all the old browsers too. I figure this is a much better solution and I've intentionally gone ahead and written something myself because I'm trying as much as possible to only use my own code. After three days of headaches, I have finally decided to ask you guys. – DylRicho Jul 02 '18 at 06:07

1 Answers1

1

You are correct you need to escape the characters for the regex.

Try to escape the game_name in the regex with two backslashes like this:

var regexp = new RegExp(game_name.replace(/\(|\)/g, "\\$&"), "i");

The reason you need the extra backslash is that the backslash has special meaning both in string literals and in regular expressions. The first one is an escape character and only the second one is being taken.

Oram
  • 1,589
  • 2
  • 16
  • 22
  • Many thanks Oram, that has worked a treat. My issue was that I couldn't work out how to escape them within the `RegExp` constructor. Again, thank you very much. :) – DylRicho Jul 02 '18 at 13:33