0

I am trying to pass the function DeleteModule two levels down. So I am passing that another component inside map as a prop. Although I did binding in the constructor, the compiler still throws an error as given below.

I tried adding a binding like : this.deleteModule = this.deleteModule.bind(this) inside the function renderListOfModules. Then too, it didnt work.

Can anyone point out what went wrong in my code?

import React from 'react';
import '../../node_modules/bootstrap/dist/css/bootstrap.css';

import  ModuleListItem from '../components/ModuleListItem';

export default class ModuleList extends React.Component{


    constructor(props) {
        super(props);
        this.state = {
            module: { title: '' },
            modules: [
                {id: 1, title: "JQuery"},
                {id: 2, title: "React"},
                {id: 3, title: "Redux"},
                {id: 4, title: "Angular"},
                {id: 5, title: "Node"}
            ]
        }
        this.titleChanged = this.titleChanged.bind(this);
        this.createModule = this.createModule.bind(this);
        this.deleteModule = this.deleteModule.bind(this);


    }

    titleChanged(event) {
        console.log(event.target.value);
        this.setState({module: {title: event.target.value, id : this.state.modules.length +1}});

    }

    createModule(){
        this.setState(
            { modules : this.state.modules.concat(this.state.module)});
        this.setState({module: {title: ""}});


    }

        deleteModule=(index)=>{
            console.log("index to remove : " + index);
            if (index > -1) {
                this.setState(
                    { modules : this.state.modules.splice(index, 1) });
            }

            // /api/module/61
            // module_id actual
        }



    editModule(index,title,  updated){
        console.log("Edit module ");
        console.log("index          : " + index);
        console.log("title          : " + title);
        console.log("updated        : " + updated);


        if (index > -1 && index  <  this.state.modules.length) {
            this.setState(
                { modules : this.state.modules.splice(index, 1) });
        }


        // to api :

        //courseid
        //title
        // updatedAt:



    }


    renderListOfModules(){
        let index = -1;


        let modules = this.state.modules.map(function(module) {
                index++;
                return <ModuleListItem
                    key={module.id}
                    id={index}
                    index={index}
                    title={module.title}
                    inEditMode={false}
                    deleteModule={this.deleteModule}/>
            }
        )

    return modules

    }

    render(){
        return(
            <div>
                <input className="form-control"
                       onChange={this.titleChanged}
                       placeholder="title"
                       value={this.state.module.title}/>
                <button
                    className="btn btn-primary btn-block"
                    onClick={this.createModule}>

                    <i className="fa fa-plus"></i>
                </button>
        <ul className="list-group">

                {this.renderListOfModules()}
            </ul>
            </div>
        );
    }
}

Note : I am using arrow function to give the delete function a component scope.

What am I doing wrong ?

Error :

    ×
←→1 of 2 errors on the page
TypeError: Cannot read property 'deleteModule' of undefined
(anonymous function)
src/container/ModuleList.js:91
  88 |             index={index}
  89 |             title={module.title}
  90 |             inEditMode={false}
> 91 |             deleteModule={this.deleteModule}/>
  92 |     }
  93 | )
  94 | 

Github code link : Code

Athul Muralidharan
  • 693
  • 1
  • 10
  • 18
  • Possible duplicate of ["this" is undefined inside map function Reactjs](https://stackoverflow.com/questions/30148827/this-is-undefined-inside-map-function-reactjs) – AndrewL64 Jun 03 '18 at 23:25
  • Probably you don't have installed the Babel transpiler needed to translate the fat arrow autobinding. – Dez Jun 03 '18 at 23:33

2 Answers2

2

Your function renderListOfModules() and your map callback are not binded so your are not passing down the component scope and wont be able to access the functions declared on it. You should bind them or declare them as arrow functions also:

renderListOfModules = () => {
    let index = -1;


    let modules = this.state.modules.map((module) => {
            index++;
            return <ModuleListItem
                key={module.id}
                id={index}
                index={index}
                title={module.title}
                inEditMode={false}
                deleteModule={this.deleteModule}/>
        }
    )

return modules

}
Facundo Larrosa
  • 3,349
  • 2
  • 14
  • 22
0

You can either add a this as a second argument like this:

let modules = this.state.modules.map(function(module) {
                index++;
                return <ModuleListItem
                    key={module.id}
                    id={index}
                    index={index}
                    title={module.title}
                    inEditMode={false}
                    deleteModule={this.deleteModule}/>
            }, this
        )

Or you can just use fat arrow function like this:

let modules = this.state.modules.map((module) => {
    index++;
    return <ModuleListItem
    key={module.id}
    id={index}
    index={index}
    title={module.title}
    inEditMode={false}
    deleteModule={this.deleteModule}/>
}
AndrewL64
  • 15,794
  • 8
  • 47
  • 79