首页 > 解决方案 > 在更改其属性后渲染数组项

问题描述

在对数组中的元素进行更改后,我在重新渲染数组中的项目时遇到问题。无论我是通过推入添加还是通过拼接删除,当数组在页面上再次呈现时,就像更多的项目被添加到数组中一样。因此,如果我推入数组,则会添加项目,但旧项目会被复制到数组中。当我删除项目时会发生类似的事情。该项目看起来已被删除,但数组中的元素显示在页面上,然后它们被复制并且被拼接的项目消失了。

我试图避免使用 location.reload('/edit.html') 来刷新页面。一种作弊。它似乎有效,但我正在尝试使用我的renderIngredients功能刷新页面。toggleIngredient当我检查一个项目时,该功能还会复制项目列表。

import { initializeEditPage, generateLastEdited } from './views'
import { updateRecipe, removeRecipe, saveRecipes, getRecipes, createIngredient } from './recipes'

const titleElement = document.querySelector('#recipe-title')
const bodyElement = document.querySelector('#recipe-body')
const removeElement = document.querySelector('#remove-recipe')
const addElement = document.querySelector('#add-recipe')
const dateElement = document.querySelector('#last-updated')
const addIngredient = document.querySelector('#new-ingredient')
const recipeStatus = document.querySelector('#recipe-status')

const recipeId = location.hash.substring(1)
const recipeOnPage = getRecipes().find((item) => item.id === recipeId)

titleElement.addEventListener('input', (e) => {
    const recipe = updateRecipe(recipeId, {
        title: e.target.value
    })
    dateElement.textContent = generateLastEdited(recipe.updatedAt)
})

bodyElement.addEventListener('input', (e) => {
    const recipe = updateRecipe(recipeId, {
        body: e.target.value
    })
    dateElement.textContent = generateLastEdited(recipe.updatedAt)
})

addElement.addEventListener('click', () => {
    saveRecipes()
    location.assign('/index.html')
})

removeElement.addEventListener('click', () => {
    removeRecipe(recipeId)
    location.assign('/index.html')
})

addIngredient.addEventListener('submit', (e) => {
    const text = e.target.elements.text.value.trim()
    e.preventDefault()

    if (text.length > 0) {
        createIngredient(recipeId, text)
        e.target.elements.text.value = ''
    }
    renderIngredients(recipeId)
    saveRecipes()
    //location.reload('/edit.html')
})

const removeIngredient = (text) => {
    const ingredientIndex = recipeOnPage.ingredients.findIndex((ingredient)=> ingredient.text === text)
    if (ingredientIndex > -1) {
        recipeOnPage.ingredients.splice(ingredientIndex, 1)
    }
    saveRecipes()
    renderIngredients(recipeId)
    //location.reload('/edit.html')
}

const toggleIngredient = (text) => {
    const ingredient = recipeOnPage.ingredients.find((ingredient) => ingredient.text === text)
    if (ingredient.included) {
        ingredient.included = false
    } else {
        ingredient.included = true
    }
    //location.reload('/edit.html')
}

const ingredientSummary = (recipe) => {
    let message
    const allUnchecked = recipeOnPage.ingredients.every((ingredient) => ingredient.included === false)
    const allChecked = recipeOnPage.ingredients.every((ingredient) => ingredient.included === true)

    if (allUnchecked) {
        message = `none`
    } else if (allChecked) {
        message = `all`
    } else {
        message = `some`
    }
    return `You have ${message} ingredients for this recipe`
}

const generateIngredientDOM = (ingredient) => {
    const ingredientEl = document.createElement('label')
    const containerEl = document.createElement('div')
    const checkbox = document.createElement('input')
    const ingredientText = document.createElement('span')
    const removeButton = document.createElement('button')
    recipeStatus.textContent = ingredientSummary(recipeOnPage)

    // Setup ingredient container
    ingredientEl.classList.add('list-item')
    containerEl.classList.add('list-item__container')
    ingredientEl.appendChild(containerEl)

    // Setup ingredient checkbox
    checkbox.setAttribute('type', 'checkbox')
    checkbox.checked = ingredient.included
    containerEl.appendChild(checkbox)
    // Create checkbox button in ingredient div
    checkbox.addEventListener('click', () => {
        toggleIngredient(ingredient.text)
        saveRecipes()
        renderIngredients(recipeId)
    })

    // Setup ingredient text
    ingredientText.textContent = ingredient.text
    containerEl.appendChild(ingredientText)

    // Setup the remove button
    removeButton.textContent = 'remove'
    removeButton.classList.add('button', 'button--text')
    ingredientEl.appendChild(removeButton)
    // Create remove button in ingredient div
    removeButton.addEventListener('click', () => {
        removeIngredient(ingredient.text)
        saveRecipes()
        renderIngredients(recipeId)
    }) 

    return ingredientEl
}

const renderIngredients = (recipeId) => {
    // Grab the ingredient display from the DOM
    const ingredientList = document.querySelector('#ingredients-display')
    const recipe = getRecipes().find((item) => {
        return item.id === recipeId
    })

    // Iterate through the list of ingredients on the page and render all items from recipeDOM
    recipe.ingredients.forEach((ingredient) => {
        const recipeDOM = generateIngredientDOM(ingredient)
        ingredientList.appendChild(recipeDOM)
    })
}

renderIngredients(recipeId)

我相信这个问题源于我的 renderIngredients 函数,但我不知道如何解决它。同样,当我刷新页面时,我想要显示的结果,但我想避免使用location.reload. 我希望该removeIngredient功能可以通过单击按钮来删除成分,并且页面会使用该renderIngredients功能刷新。还期望该toggleIngredient功能仅在我检查的成分旁边显示一个复选框,但这不是正在发生的事情。当我使用该addIngredient功能时,同样的事情发生了,正在添加成分,但是已经在页面上的成分正在被复制。

标签: javascriptarraysrendering

解决方案


我猜你想在再次添加元素之前清除列表:

ingredientList.innerHTML = "";

推荐阅读