Kevin Durant Kevin Durant - 27 days ago 8
Javascript Question

ES6 includes but case insensitive

I know I can loop through array and just change value

toLowerCase()
.

I'm curious if there's a
reactjs
or
es6
method that can check if the value is in array.

On addTodo function. You can see that I use includes but this method is case sensitive.

Here's what I have

class Todo extends React.Component {
render() {
return (
<div className="todo">
<input type="checkbox" />
<p>{this.props.children}</p>
</div>
);
}
}

class App extends React.Component {
constructor(props) {
super(props);

this.todos = [
'Get Up from bed',
'Eat Breakfast'
];
}

eachTodo(task, i) {
return (
<Todo key={i} index={i}>{task}</Todo>
)
}

addToDo() {
let task_title = this.refs.newTodo.value;

if(task_title !== '') {
let arr = this.todos;

var arr_tlc = this.todos.map((value) => {
return value.toLowerCase();
})

if(arr_tlc.indexOf(task_title.toLowerCase()) === -1) {
arr.push(task_title);

this.setState({
todos: arr
});
}
}
}

render() {
return (
<div className="main-app">
<input ref="newTodo" placeholder="Task"/>
<button onClick={this.addToDo.bind(this)}>Add Todo</button>

<div className="todos">
{this.todos.map(this.eachTodo)}
</div>
</div>

);
}
}


Any help would be appreciated. Thanks!

Answer

I would suggest using a Map instead of an array for your todo list. A Map has the advantage that it provides key-based look-up in constant time, and does not store duplicate entries with the same key. You could then use the lower case variant as the key, and the original (mixed-case) string as the value for that key.

You could define todos as a Map instead of an array, and use the lower case string as the key:

constructor(props) {
    super(props);
    this.todos = new Map();
    this.addToDo('Get Up from bed'); 
    this.addToDo('Eat Breakfast');
}

Then, to add the task becomes very straightforward, as a Map overwrites duplicates:

addToDo() {
    this.todos.set(task_title.toLowerCase(), task_title);
    this.setState({
        todos: this.todos
    });
 }

In rendering you would need to use .forEach, as .map is not defined for Map objects:

<div className="todos">
    {this.todos.forEach(this.eachTodo)}
</div>

Which means the eachToDo method will receive a pair of strings (an array), instead of a string, and we want to display the second of the pair, so using index [1]:

eachTodo(task, i) {
    return (
        <Todo key={i} index={i}>{task[1]}</Todo>
    )
}