-1

I'm trying to set up a search bar that searches a table made by looping data brought from an API either by name or by email , but I can't find were I'm going wrong. The console shows me uncaught ReferenceError: sBar is not defined at window.onload Please try to keep in mind that I'm quite a newbie in JS. I'm really sorry is this is silly but I've tried my best and I'm extremely frustrated at my inability to see the mistake

This is my HTML

<body>
  <div>
    <label for="finder">Find User:</label>
    <input type="search" id="searchInput" name="sInput" placeholder="Search 
    user">
    <button id="sButton">Search</button>
  </div>
  <table class="table table-responsive">
    <thead class="thead-dark">
      <tr>
        <th scope="col">Id</th>
        <th scope="col">Name</th>
        <th scope="col">Username</th>
        <th scope="col">Email</th>
        <th scope="col">Address</th>
        <th scope="col">Phone</th>
        <th scope="col">Website</th>
        <th scope="col">Company</th>
      </tr>
    </thead>
    <tbody name="tTable">
    </tbody>
  </table>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js">
</script>
<script src="script.js">
</script>

Mi JS

window.onload = function(){    

    let uList = document.querySelector('[name =tTable]');  

    fetchCall('https://jsonplaceholder.typicode.com/users', getUsers);
    sButton.addEventListener('click', 
    fetchCall('https://jsonplaceholder.typicode.com/users', sBar), false);


  function sBar(getObject) {
    let sUser = getObject;
    let inputBar = document.getElementById("searchInput");
    let text = inputBar.textContent;
    let textView = text.toUpperCase();
    for (let i = 0; i < getObject.length; i++) {
         let uObject = sUser[i];
      if (textView == uObject.name || textView == uObject.email) {
        let new_tTable = document.createElement('tbody');
        uList.parentNode.replaceChild(new_tTable, uList)

        let row = uList.insertRow();   
        let idInput = document.createElement('td');
        let nameInput = document.createElement('td');     
        let usernameInput = document.createElement('td');    
        let emailInput = document.createElement('td');      
        let cityInput = document.createElement('td');      
        let phoneInput = document.createElement('td');      
        let websiteInput = document.createElement('td');      
        let companyInput = document.createElement('td');      

        idInput.textContent = uObject.id;
        nameInput.textContent = uObject.name;
        usernameInput.textContent = uObject.username;
        emailInput.textContent = uObject.email;
        cityInput.textContent = uObject.address.city;
        phoneInput.textContent = uObject.phone;
        websiteInput.textContent = uObject.website;
        companyInput.textContent = uObject.company.name;
        row.appendChild(idInput);
        row.appendChild(nameInput);
        row.appendChild(usernameInput);
        row.appendChild(emailInput);
        row.appendChild(cityInput);
        row.appendChild(phoneInput);
        row.appendChild(websiteInput);
        row.appendChild(companyInput);  
     } else {
       alert("User not found");         
     }
   }
} 


  function fetchCall(url, fn){
    fetch(url)
        .then(function(response){
            return response.json();
        })
        .then(function(endPoint){
            fn(endPoint);
        })
        .catch(function(error){
            console.error(error);
        })
    }

  function getUsers(getObject) {
    let user = getObject;      
      for (let i = 0; i < getObject.length; i++) {
        let userObject = user[i];
        let row = uList.insertRow();   
        let idInput = document.createElement('td');
        let nameInput = document.createElement('td');     
        let usernameInput = document.createElement('td');    
        let emailInput = document.createElement('td');      
        let cityInput = document.createElement('td');      
        let phoneInput = document.createElement('td');      
        let websiteInput = document.createElement('td');      
        let companyInput = document.createElement('td');      

        idInput.textContent = userObject.id;
        nameInput.textContent = userObject.name;
        usernameInput.textContent = userObject.username;
        emailInput.textContent = userObject.email;
        cityInput.textContent = userObject.address.city;
        phoneInput.textContent = userObject.phone;
        websiteInput.textContent = userObject.website;
        companyInput.textContent = userObject.company.name;
        row.appendChild(idInput);
        row.appendChild(nameInput);
         row.appendChild(usernameInput);
         row.appendChild(emailInput);
         row.appendChild(cityInput);
         row.appendChild(phoneInput);
         row.appendChild(websiteInput);
         row.appendChild(companyInput);        
        }
      } 
    }
Nyom
  • 114
  • 7
  • `name` attribute is meaningless in most of the elements, only form control elements and window elements are recognized by name. Use `id` for other elements. What comes to the actual problem, it is not reproducable with the code in the post. – Teemu Jan 22 '19 at 05:20
  • "_sBar is not defined at window.onload_" doesn't describe the problem correctly, should be "sBar is not defined on "Search" button click" ... Don't use inline events, add the event for the button inside the `window.onload` function. Also adding a click listener to `sButton` fails, `fetchCall` doesn't return anything to be used as an event handler function. – Teemu Jan 22 '19 at 05:27

4 Answers4

1

When you set an event, you call the function, but you need to bind it.

sButton.addEventListener('click', fetchCall.bind(this, 'https://jsonplaceholder.typicode.com/users', sBar), false);

I also recommend to make a function in the global scope.

uList = document.querySelector('[name =tTable]');

window.onload = function () {
    fetchCall('https://jsonplaceholder.typicode.com/users', getUsers);
    sButton.addEventListener('click', fetchCall.bind(this, 'https://jsonplaceholder.typicode.com/users', sBar), false);
}

function sBar(getObject) {
    let sUser = getObject;
    let inputBar = document.getElementById("searchInput");
    let text = inputBar.textContent;
    let textView = text.toUpperCase();
    for (let i = 0; i < getObject.length; i++) {
        let uObject = sUser[i];
        if (textView == uObject.name || textView ==
            uObject.email) {
            let new_tTable = document.createElement('tbody');
            uList.parentNode.replaceChild(new_tTable, uList)


            let row = uList.insertRow();
            let idInput = document.createElement('td');
            let nameInput = document.createElement('td');
            let usernameInput = document.createElement('td');
            let emailInput = document.createElement('td');
            let cityInput = document.createElement('td');
            let phoneInput = document.createElement('td');
            let websiteInput = document.createElement('td');
            let companyInput = document.createElement('td');

            idInput.textContent = uObject.id;
            nameInput.textContent = uObject.name;
            usernameInput.textContent = uObject.username;
            emailInput.textContent = uObject.email;
            cityInput.textContent = uObject.address.city;
            phoneInput.textContent = uObject.phone;
            websiteInput.textContent = uObject.website;
            companyInput.textContent = uObject.company.name;
            row.appendChild(idInput);
            row.appendChild(nameInput);
            row.appendChild(usernameInput);
            row.appendChild(emailInput);
            row.appendChild(cityInput);
            row.appendChild(phoneInput);
            row.appendChild(websiteInput);
            row.appendChild(companyInput);
        } else {
            alert("User not found");
        }
    }
}


function fetchCall(url, fn) {
    fetch(url)
        .then(function (response) {
            return response.json();
        })
        .then(function (endPoint) {
            fn(endPoint);
        })
        .catch(function (error) {
            console.error(error);
        })
}

function getUsers(getObject) {
    let user = getObject;
    for (let i = 0; i < getObject.length; i++) {
        let userObject = user[i];
        let row = uList.insertRow();
        let idInput = document.createElement('td');
        let nameInput = document.createElement('td');
        let usernameInput = document.createElement('td');
        let emailInput = document.createElement('td');
        let cityInput = document.createElement('td');
        let phoneInput = document.createElement('td');
        let websiteInput = document.createElement('td');
        let companyInput = document.createElement('td');

        idInput.textContent = userObject.id;
        nameInput.textContent = userObject.name;
        usernameInput.textContent = userObject.username;
        emailInput.textContent = userObject.email;
        cityInput.textContent = userObject.address.city;
        phoneInput.textContent = userObject.phone;
        websiteInput.textContent = userObject.website;
        companyInput.textContent = userObject.company.name;
        row.appendChild(idInput);
        row.appendChild(nameInput);
        row.appendChild(usernameInput);
        row.appendChild(emailInput);
        row.appendChild(cityInput);
        row.appendChild(phoneInput);
        row.appendChild(websiteInput);
        row.appendChild(companyInput);
    }
}
  • Just made the changes, but I still have the same error of sBar not defined. Tried IE, FF and Chrome – Nyom Jan 22 '19 at 17:14
0

You may want to define window.onload and other functions separately.

window.onload = function(){    

    let uList = document.querySelector('[name =tTable]');  

    fetchCall('https://jsonplaceholder.typicode.com/users', getUsers);
    sButton.addEventListener('click', 
    fetchCall('https://jsonplaceholder.typicode.com/users', sBar), false);
};

  function sBar(getObject) {
    let sUser = getObject;
    let inputBar = document.getElementById("searchInput");
    let text = inputBar.textContent;
    let textView = text.toUpperCase();
    for (let i = 0; i < getObject.length; i++) {
         let uObject = sUser[i];
        if (textView == uObject.name || textView == 
       uObject.email) {
        let new_tTable = document.createElement('tbody');
        uList.parentNode.replaceChild(new_tTable, uList)


        let row = uList.insertRow();   
        let idInput = document.createElement('td');
        let nameInput = document.createElement('td');     
        let usernameInput = document.createElement('td');    
        let emailInput = document.createElement('td');      
        let cityInput = document.createElement('td');      
        let phoneInput = document.createElement('td');      
        let websiteInput = document.createElement('td');      
        let companyInput = document.createElement('td');      

        idInput.textContent = uObject.id;
        nameInput.textContent = uObject.name;
        usernameInput.textContent = uObject.username;
        emailInput.textContent = uObject.email;
        cityInput.textContent = uObject.address.city;
        phoneInput.textContent = uObject.phone;
        websiteInput.textContent = uObject.website;
        companyInput.textContent = uObject.company.name;
        row.appendChild(idInput);
        row.appendChild(nameInput);
         row.appendChild(usernameInput);
         row.appendChild(emailInput);
         row.appendChild(cityInput);
          row.appendChild(phoneInput);
         row.appendChild(websiteInput);
         row.appendChild(companyInput);  
          } else{
           alert("User not found");
               }
       }
   } 


  function fetchCall(url, fn){
    fetch(url)
        .then(function(response){
            return response.json();
        })
        .then(function(endPoint){
            fn(endPoint);
        })
        .catch(function(error){
            console.error(error);
        })
    }

  function getUsers(getObject) {
    let user = getObject;      
      for (let i = 0; i < getObject.length; i++) {
        let userObject = user[i];
        let row = uList.insertRow();   
        let idInput = document.createElement('td');
        let nameInput = document.createElement('td');     
        let usernameInput = document.createElement('td');    
        let emailInput = document.createElement('td');      
        let cityInput = document.createElement('td');      
        let phoneInput = document.createElement('td');      
        let websiteInput = document.createElement('td');      
        let companyInput = document.createElement('td');      

        idInput.textContent = userObject.id;
        nameInput.textContent = userObject.name;
        usernameInput.textContent = userObject.username;
        emailInput.textContent = userObject.email;
        cityInput.textContent = userObject.address.city;
        phoneInput.textContent = userObject.phone;
        websiteInput.textContent = userObject.website;
        companyInput.textContent = userObject.company.name;
        row.appendChild(idInput);
        row.appendChild(nameInput);
         row.appendChild(usernameInput);
         row.appendChild(emailInput);
         row.appendChild(cityInput);
         row.appendChild(phoneInput);
         row.appendChild(websiteInput);
         row.appendChild(companyInput);        
        }
      } 
Prashant Zombade
  • 482
  • 3
  • 15
0

You have attached a callback sBar() to anonchange event of the search input. But there is no definition of an sBar() function (Note that it does not accept an argument/parameter). You only defined a function that with the same name, "sBar", that accepts (requires) a parameter that you named as getObject.

Remove the parameter "getObject" and modify the first few lines for getting the current inputted text in the search input. Example code to get the value of your search input is:

var value = document.getElementById("searchInput").value;

Side Note:

You might probably need to use another event emitter instead of onchange. This only fires when you leave focus on the input element and not on actual input.

If you want to track changes as they type, use "onkeydown". If you need to trap paste operations with the mouse, use "onpaste" (IE, FF3) and "oninput" (FF, Opera, Chrome, Safari1).

Please see it from this link

Alex Pappas
  • 2,377
  • 3
  • 24
  • 48
0

async/await & fetch()

The core function is based onasync/await and fetch(), go to the link above for special syntax.

I honestly don't know how to approach all of the issues with OP (Original Post) code. In general, you should consider the process in steps:

  1. Get the JSON from the URL. Do you know for sure that fetchAll() works?

  2. Once you can get the JSON with fetchCall() pass the JSON over to getUser()

  3. If fetchCall() returns a value (it appears that it does...) use the whole function as a value.

  4. Event listeners and handlers have a particular signature you must adhere to and using a named callback or an anonymous callback matters:

Named Callback (No Parameters*)

DOMObj.addEventListener('event', namedFunction);
function namedFunction(e) {...

Named Callback (With Parameters)

DOMObj.addEventListener('event', function(e) {
  namedFunction(num, str);
});
function namedFunction(num, str) {...

Anonymous Callback

DOMObj.addEventListener('event', function(e) {...

The following demo uses async function getUser(url, id) to streamline the Promises, use fetch(), and extract the JSON one user id at a time. The function getData(json) is returned by getUser() along with the JSON.

The search input has been change to type='number' since user's are reference by their user.id property. It's also wrapped in a <form> tag so the callback function findUser(url, id) will be triggered by a submit event. It is basically a function wrapper for getUser().


Demo

<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet">
<style>
fieldset.fieldset {width:max-content;padding: 10px 0 0}
input.input, label.label {display:inline-block;font:inherit;width:9ch;height:30px;line-height:30px;vertical-align:middle;text-align:center;}
input.input {width:6ch;padding-right:0;margin-right:8px}
input.button {font:inherit;height: 30px;line-height:20px;}
</style>
</head>
<body>
  <main class='container'>
    <section class='row'>
      <form id='main' class='form inline-form'>
        <fieldset class='fieldset form-group'>
          <label class='label control-label float-left' for="find">User ID:</label>
          <input id="find" class='input form-control float-left' type="number" min='1' max='10'>
          <input class="button btn btn-dark btn-sm float-left" type='submit' value='Find'>
       </fieldset>
    </form>
  </section>
  <section class='row'>
  <table class="table table-responsive">
    <thead class="thead-dark">
      <tr>
        <th scope="col">ID</th>
        <th scope="col">Name</th>
        <th scope="col">Username</th>
        <th scope="col">Email</th>
        <th scope="col">Phone</th>
        <th scope="col">Company</th>
        <th scope="col">City</th>
        <th scope="col">Website</th>
      </tr>
    </thead>
  </table>
 </section>
</main>
<script>

const main = document.forms[0];

const getData = (user) => {
  const uList = document.querySelector('.table');
  let row = uList.insertRow();  
  let cell = idx => row.insertCell(idx);
  
  for (let i = 0; i < 8; i++) {
    let C = cell(i);
    switch(i) {
      case 0:
      user.id = user.id > 9 ? "" + user.id: "0" + user.id;
      C.textContent = user.id;
      break;
      case 1:
      C.textContent = user.name;
      break;
      case 2:
      C.textContent = user.username;
      break;
      case 3:
      C.textContent = user.email;
      break;
      case 4:
      C.textContent = user.phone;
      break;
      case 5:
      C.textContent = user.company.name;
      break;
      case 6:
      C.textContent = user.address.city;
      break;
      case 7:
      C.textContent = user.website;
      break;
      default:
      break;
    }
  } 
};

const getUser = async (url, id) => { 
  const response = await fetch(`${url}${id}`);
  const json = await response.json();
  return getData(json);
};

/*/ For debugging -- an IIFE variables are private. Parameters are required.
(async (u, i) => {
  const json = await getUser(u, i);
  console.log(json);
})(url, id);
/*/

const findUser = (e) => {
  e.preventDefault();
  const url = 'https://jsonplaceholder.typicode.com/users/';
  let id = Number(e.currentTarget.find.value);
  getUser(url, id);
};

main.addEventListener('submit', findUser);

</script>
</body>
</html>
zer00ne
  • 41,936
  • 6
  • 41
  • 68