简体   繁体   English

JavaScript:单击“编辑”按钮时,console.log 显示“未定义”

[英]JavaScript: when clicking on 'edit' button, the console.log reads “undefined”

I'm using a Rails API backend and a JavaScript frontend.我正在使用 Rails API 后端和 JavaScript 前端。 I have a form and a list of Materials, and I am trying to make each Material editable.我有一个表单和一个材质列表,我正在尝试使每个材质都可编辑。 I have a click event set up right now, attempting to find the ID of the Material I click on, but the console.log shows "undefined".我现在设置了一个点击事件,试图找到我点击的材料的 ID,但 console.log 显示“未定义”。

Can someone help me so when I click on a Material, it shows what Material I'm clicking on?有人可以帮助我,所以当我点击一个材质时,它会显示我点击的材质吗?

index.js file: index.js 文件:

const materialIndex = "http://localhost:3000/api/v1/materials"
const categoryIndex = "http://localhost:3000/api/v1/categories"

document.addEventListener('DOMContentLoaded', () => {
    getMaterials()

    const createMaterialForm = document.querySelector("#create-material-form")

    createMaterialForm.addEventListener("submit", (e) => createFormHandler(e))

    const materialContainer = document.querySelector('#material-container')
    materialContainer.addEventListener('click', e => {
        //debugger
        const id = parseInt(e.target.dataset.id)
        const material = Material.findById(id)
        console.log(material)
    })

})

function getMaterials() {
    fetch(materialIndex) //get request
    .then(response => response.json())
    .then(materials => {
        materials.data.forEach(material => {
            let newMaterial = new Material(material, material.attributes)
            //creating new instance of material class, goes to constructor and gets pushed into an array
            document.querySelector('#material-container').innerHTML += newMaterial.renderMaterialCard()
        })
        // want to create category cards, where each resource populates in each category card once added //
    })
}

function createFormHandler(e) { //grabs all values of materials submitted by user
    e.preventDefault()
    const nameInput = document.querySelector('#input-name').value
    const descriptionInput = document.querySelector('#input-description').value
    const urlInput = document.querySelector('#input-url').value
    const categoryId = parseInt(document.querySelector('#categories').value)
    postFetch(nameInput, descriptionInput, urlInput, categoryId)
}

function postFetch(name, description, url, category_id) {
    const bodyData = {name, description, url, category_id}
    fetch(materialIndex, {
        method: "POST",
        headers: {"Content-Type": "application/json"},
        body: JSON.stringify(bodyData)
    })
    .then(response => response.json())
    .then(material => {
        const materialData = material.data
        let newMaterial = new Material(materialData, materialData.attributes)
        
        document.querySelector('#material-container').innerHTML += newMaterial.renderMaterialCard()
    })

    //patch or delete request
    
}

material.js file: material.js 文件:

class Material {
    constructor(material, materialAttributes) {
        this.id = material.id
        this.name = materialAttributes.name
        this.description = materialAttributes.description
        this.url = materialAttributes.url
        this.category = materialAttributes.category
        Material.all.push(this)
    }

    renderMaterialCard() {
        return `
            <div data-id=${this.id}>
            <h3>${this.name}</h3>
            <p>${this.description}</p>
            <p><small><a href="${this.url}">${this.url}</a></small></p>
            <p>${this.category.title}</p>
            <button data-id=${this.id}>edit</button>
            </div>
            <br><br>`
    }

    static findById(id) {
        return this.all.find(material => material.id === id)
    }


    renderPatchForm() {
        return `
            <form data-id=${this.id} >
                <h3>Edit the Resource</h3>

                <label>Name</label>
                <input id='input-name' type="text" name="name" value="${this.name}" class="input-name">
                <br><br>

                <label>Description</label>
                <textarea id='input-description' name="description" rows="8" cols="80" value="">${this.description}</textarea>
                <br><br>

                <label>URL</label>
                <input id='input-url' type="text" name="url" value="${this.url}" class="input-text">
                <br><br>

                <label>Category</label>
                <select id="categories" name="categories" value="${this.category.name}">
                    <option value="1">Criminal Justice Reform</option>
                    <option value="2">Bail Funds</option>
                    <option value="3">Clothing</option>
                    <option value="4">Organizations</option>
                    <option value="5">Mutual Aid</option>
                    <option value="6">Fundraisers</option>
                    <option value="7">Petitions</option>
                    <option value="8">Articles</option>
                    <option value="9">Artists</option>
                    <option value="10">Instagram</option>
                </select>
                <br><br>

                <input id='edit-button' type="submit" name="submit" value="Edit Material" class="submit">
            </form> `
  }
}

Material.all = []

index.html file: index.html 文件:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>Beneficial Resources</title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="style.css">
        <script type="text/javascript" src="src/material.js"></script>
        <script type="text/javascript" src="src/index.js"></script>
    </head>
    <body>

        <div class="form-container">
            <form id="create-material-form">
                <center>
                <h3>Add a new Resource</h3>

                <input id='input-name' type="text" name="name" value="" placeholder="Enter the Resource name" class="input-text">
                <br><br>
                <textarea id='input-description' name="description" rows="8" cols="80" value="" placeholder="Enter the description of your Resource..."></textarea>
                <br><br>
                <input id="input-url" type="text" name="url" value="" placeholder="Enter the URL of your Resource..." class="input-text">
                <br>

                <h3>What Category is your Resource?</h3>
                <select id="categories" name="categories">
                    <option value="1">Criminal Justice Reform</option>
                    <option value="2">Bail Funds</option>
                    <option value="3">Clothing</option>
                    <option value="4">Organizations</option>
                    <option value="5">Mutual Aid</option>
                    <option value="6">Fundraisers</option>
                    <option value="7">Petitions</option>
                    <option value="8">Articles</option>
                    <option value="9">Artists</option>
                    <option value="10">Instagram</option>
                </select>
                <br>

                <input id="create-button" type="submit" name="submit" value="Add New Resource" class="submit">

            </form>
        </center>
            <br>
            <br>
        </div>

        <div id="material-container">

        </div>

        <div id="update-material">

        </div>
        
    </body>
</html>

Just looking over you code只是看着你的代码

    static findById(id) {
        return this.all.find(material => material.id === id)
    }

I would try using filter instead of find, another thing work checking is the type of material.id and the type of id.我会尝试使用过滤器而不是查找,另一件工作检查是 material.id 的类型和 id 的类型。 If they're different types like material.id = '1' and the id is int 1 you can just use a double equals, material.id == id.如果它们是不同的类型,例如 material.id = '1' 并且 id 为 int 1,则您可以使用双等号,material.id == id。

    static findById(id) {
        return this.all.filter(material => material.id == id)
    }

I notice you are adding an event listener to the material container.我注意到您正在向材质容器添加一个事件侦听器。 This will be triggered on anything clicked inside and those targets wont have the data-id attribute on them.这将在点击内部的任何内容时触发,并且这些目标上不会有data-id属性。 What you might want to do is find the .closest('[data-id]') of the target clicked.您可能想要做的是找到点击的目标的.closest('[data-id]')

const materialContainer = document.querySelector('#material-container')
    materialContainer.addEventListener('click', e => {
        //debugger
        const id = parseInt(e.target.closest('[data-id]').dataset.id);
        const material = Material.findById(id)
        console.log(material)
    })

This wont work in IE11 or older browser because they dont implement .closest() .这在 IE11 或更旧的浏览器中不起作用,因为它们没有实现.closest()

If you need to support older browsers, you might want to use a polyfill or figure out some other way to delegate events.如果您需要支持较旧的浏览器,您可能需要使用 polyfill 或找出其他方法来委托事件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM