Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

Phonebook App: if a number is added to an already existing user, the new number will

Options
  • 08-06-2021 5:37pm
    #1
    Registered Users Posts: 4,573 ✭✭✭


    Hi guys,

    Currently have a phonebook App created with React, that will take a name and a number from a form and display it on screen and also store the data on a server.

    I am looking to improve the functionality so that if a number is added to an already existing user, the app will ask if you would like to replace the old number with the new number.

    Picture added below of what app will look like when functioning correctly.

    Here is my function for adding an entry to the phone book
    const addName = (event) => {
    event.preventDefault()
    const nameObject = {
      name: newName,
      number: newNumber,
    }
    
    if (persons.some(person =>person.name ===
      `${newName}`) )
      
     {
      alert(`${newName}` + " is already added to phonebook, replace the old number with a new one?")
    changeNumberOf(persons.id)
     
     }
     else
     {
      personsService
       .create(nameObject)
       .then(returnedName => {
        setPersons(persons.concat(returnedName))
        setNewName('')
        setNewNumber('')
    

    I created a new function to update the user with the new phone number
    const changeNumberOf = id => {
      const url = `http://localhost:3001/persons/${id}`
      const person = persons.find(n => n.id === id)
      const changedPerson = { ...person} // here I need to update to the new number
    
      axios.put(url, changedPerson).then(response => {
        setPersons(persons.map(person => person.id !== id ? person : response.data))
      })
    }
    

    The errors I am getting are
    PUT http://localhost:3001/persons/undefined 404 (Not Found)
    Uncaught (in promise) Error: Request failed with status code 404
    at createError (createError.js:16)
    at settle (settle.js:17)
    at XMLHttpRequest.handleLoad (xhr.js:62)

    I think my problem is I'm not passing the Id of the entry I want to change to my new function properly

    changeNumberOf(persons.id)

    If I console.log(persons.id) where I call that function it returns "undefined"

    So I guess my question is how will I get the id of the entry I want to change from the addName function?

    So I can then pass it on to my changeNumberOf function.

    Appreciate any help.

    Will post entire code for app below


Comments

  • Registered Users Posts: 4,573 ✭✭✭enfant terrible


    import React, { useState, useEffect } from 'react'
    import axios from 'axios'
    import personsService from './services/persons'
    
    
    
    
    
    const App = () => {
      const [persons, setPersons] = useState([
       ])
      const [ newName, setNewName ] = useState('')
      const [ newNumber, setNewNumber] = useState('')
      const [ searchTerm, setSearchTerm] = useState('')
    
    
      useEffect(() => {
        personsService
        .getAll()
        .then(currentNames => {
          setPersons(currentNames)
        })
    }, [])
    
      const addName = (event) => {
        event.preventDefault()
        const nameObject = {
          name: newName,
          number: newNumber,
        }
        
        if (persons.some(person =>person.name ===
          `${newName}`) )
          
         {
          alert(`${newName}` + " is already added to phonebook, replace the old number with a new one?")
          console.log(persons.id)
          changeNumberOf(persons.id)
          
          
        
         }
         else
         {
          personsService
           .create(nameObject)
           .then(returnedName => {
            setPersons(persons.concat(returnedName))
            setNewName('')
            setNewNumber('')
            console.log(persons.id)
      })
         }
      } 
      const handleNewName = (event) => {
       // console.log(event.target.value)
        setNewName(event.target.value)
      }
    
      const handleNewNumber = (event) => {
        setNewNumber(event.target.value)
      }
    
       const deletePersons = id => {
        const requestOptions = {
          method: 'DELETE'
        };
        fetch("http://localhost:3001/persons/" + id , requestOptions)
          personsService 
          .getAll()
          .then(initialNames => {
            setPersons(initialNames)
          }
          )}
          
         const changeNumberOf = id => {
          const url = `http://localhost:3001/persons/${id}`
          const person = persons.find(n => n.id === id)
          const changedPerson = { ...person}
        
          axios.put(url, changedPerson).then(response => {
            setPersons(persons.map(person => person.id !== id ? person : response.data))
          })
        }
    
    
      
      return (
        
        <div classname="App">
          <h2>Phonebook</h2>
          <input 
          type="text" 
          placeholder="Search..."
          onChange={event => {setSearchTerm(event.target.value)}} />
            
    
          <h2>Add a new</h2>
          <form onSubmit={addName}>
            <div>
              name: <input 
              value={newName}
              onChange={handleNewName}
              />
            </div>
            <div>
              number: <input
              value={newNumber}
              onChange={handleNewNumber}
              />
            </div>
            <div>
              <button type="submit">add</button>
            </div>
          </form>
          
          <h2>Numbers</h2>
          {persons.filter((val) => {
              if (searchTerm == "") {
            return val
              } 
              else if (val.name.toLowerCase().includes(searchTerm.toLowerCase())) {
                return val
              }
             }) .map(person => 
              <div classname="user">
              <li key={person.name}>{person.name}{person.number}
              </li>
            </div>
          
            )
            }
        </div>
      )
    }
    
    export default App
    


  • Registered Users Posts: 6,149 ✭✭✭Talisman


    You have a conditional statement that tests whether at least one element in the persons array passes the test for matching the name.
    if (persons.some(person =>person.name ===`${newName}`) ) {
      // code
    }
    

    In the event that the conditional statement is true you need to capture the value of the id property of that person object.

    If persons is an array of entries, then you want the id of the entry not of the container. The container is persons and doesn't have the id property which is why you see get an undefined result.

    The following piece of code uses the findIndex array method to get the index value of the first array element that matches the name. The findIndex method returns -1 if there is no match found so you can use this in your conditional statement.
    const isSameName = (element) => element.name ===`${newName}`;
    const matchingIndex = persons.findIndex(isSameName);
    if (matchingIndex > -1) {
      // use persons[matchingIndex] in this code block
    }
    


  • Registered Users Posts: 4,573 ✭✭✭enfant terrible


    Talisman wrote: »
    You have a conditional statement that tests whether at least one element in the persons array passes the test for matching the name.
    if (persons.some(person =>person.name ===`${newName}`) ) {
      // code
    }
    

    In the event that the conditional statement is true you need to capture the value of the id property of that person object.

    If persons is an array of entries, then you want the id of the entry not of the container. The container is persons and doesn't have the id property which is why you see get an undefined result.

    The following piece of code uses the findIndex array method to get the index value of the first array element that matches the name. The findIndex method returns -1 if there is no match found so you can use this in your conditional statement.
    const isSameName = (element) => element.name ===`${newName}`;
    const matchingIndex = persons.findIndex(isSameName);
    if (matchingIndex > -1) {
      // use persons[matchingIndex] in this code block
    }
    

    Thanks Talisman,

    I now have the index value of element I need to change(matchingIndex) with the new number(`${newNumber}`)

    Just trying to put it all together now but have a Syntaxerror
    SyntaxError: C:\Users\Nick\part2.6\src\App.js: Unexpected token, expected "," (39:49)

    This is my code to update the entry with the new number
    if (persons.some(person =>person.name ===
          `${newName}`) )
          
         {
          const isSameName = (element) => element.name ===`${newName}`;
          const matchingIndex = persons.findIndex(isSameName);
          if (matchingIndex > -1) {
            const changedPerson = {...person, persons[matchingIndex.number]: `${newNumber}`}
          
          }
    


    This is how my persons array is structured

    [
    {
    "name": "nick",
    "number": "75675667",
    "id": 1
    },
    {
    "name": "",
    "number": "",
    "id": 2
    },
    {
    "name": "nick",
    "number": "546546",
    "id": 3
    },
    {
    "name": "hvhj",
    "number": "v876876",
    "id": 4
    },
    {
    "name": "khb",
    "number": "8767687",
    "id": 5
    },
    {
    "name": "nickey",
    "number": "76576567",
    "id": 6
    },
    {
    "name": "paulina",
    "number": "76576",
    "id": 7
    }
    ]


  • Registered Users Posts: 6,149 ✭✭✭Talisman


    The code I posted was to replace this code block:
    if (persons.some(person => person.name === `${newName}`)) {
      alert(`${newName}` + " is already added to phonebook, replace the old number with a new one?")
      console.log(persons.id)
      changeNumberOf(persons.id)
    }
    

    The changes would look something like this:
    const isSameName = (element) => element.name === `${newName}`;
    const matchingIndex = persons.findIndex(isSameName);
    if ((matchingIndex > -1) && confirm(`${newName} is already added to phonebook, replace the old number with a new one?`)) {
      // a matching name was found and we want to replace the number
      console.log(persons[matchingIndex].id)
      changeNumberOf(persons[matchingIndex].id)
    }
    

    Using the data in persons array you provided as an example:
    If the value of newName is "nick" then matchingIndex is going to be set a value of 0 because findIndex() matches on the first element of the array and JavaScript uses zero based indexes for containers.

    The conditional statement contains two conditions, both of which require a true value for the code block inside the curly braces to be executed.

    (matchingIndex > -1) : matchingIndex is 0. Is 0 > -1?

    The answer is Yes so the second condition is evaluated.

    confirm(`${newName} is already added to phonebook, replace the old number with a new one?`)

    This pops a dialog box with a prompt and two buttons 'OK' and 'Cancel'. Clicking 'OK' returns a boolean true value, 'Cancel' returns false.

    So in order for the person to be updated we need to click 'OK'.

    The object to be changed is persons[0]:
    {
      "name": "nick",
      "number": "75675667",
      "id": 1
    }
    

    The console.log() statement should display 1, the value of persons[0].id

    Finally the changeNumberOf() function is executed.

    You need to be aware that having more than one object with the same value for name will always result in the first one being found by the findIndex() method.


  • Registered Users Posts: 4,573 ✭✭✭enfant terrible


    Talisman wrote: »
    The code I posted was to replace this code block:
    if (persons.some(person => person.name === `${newName}`)) {
      alert(`${newName}` + " is already added to phonebook, replace the old number with a new one?")
      console.log(persons.id)
      changeNumberOf(persons.id)
    }
    

    The changes would look something like this:
    const isSameName = (element) => element.name === `${newName}`;
    const matchingIndex = persons.findIndex(isSameName);
    if ((matchingIndex > -1) && confirm(`${newName} is already added to phonebook, replace the old number with a new one?`)) {
      // a matching name was found and we want to replace the number
      console.log(persons[matchingIndex].id)
      changeNumberOf(persons[matchingIndex].id)
    }
    

    Using the data in persons array you provided as an example:
    If the value of newName is "nick" then matchingIndex is going to be set a value of 0 because findIndex() matches on the first element of the array and JavaScript uses zero based indexes for containers.

    The conditional statement contains two conditions, both of which require a true value for the code block inside the curly braces to be executed.

    (matchingIndex > -1) : matchingIndex is 0. Is 0 > -1?

    The answer is Yes so the second condition is evaluated.

    confirm(`${newName} is already added to phonebook, replace the old number with a new one?`)

    This pops a dialog box with a prompt and two buttons 'OK' and 'Cancel'. Clicking 'OK' returns a boolean true value, 'Cancel' returns false.

    So in order for the person to be updated we need to click 'OK'.

    The object to be changed is persons[0]:
    {
      "name": "nick",
      "number": "75675667",
      "id": 1
    }
    

    The console.log() statement should display 1, the value of persons[0].id

    Finally the changeNumberOf() function is executed.

    You need to be aware that having more than one object with the same value for name will always result in the first one being found by the findIndex() method.

    Thanks again Talisman,

    I updated my changeNumberof function as below and all working great now
    const changedPerson = { ...person, number: `${newNumber}`}
    


  • Advertisement
  • Registered Users Posts: 6,149 ✭✭✭Talisman


    Glad to see it's working out now. Here's a suggestion to help you on your journey. Install an offline documentation browser like Zeal it will help you to find the documentation for methods and functions in the various frameworks that you will be using. If you are using Visual Studio Code as your development environment there is a plugin called Dash that integrates it so you can find the documentation from within your code. Little things like this can speed up your learning process and eliminate some of the early frustrations while learning to code something for yourself.


Advertisement