0

I am currently trying to add a feature where when I click the name of a user in the table it will display all of the posts made by that User however I am completely stumped. The url for the posts is https://jsonplaceholder.typicode.com/posts

I currently have the table set up and will attach images of the table and code below.

Here is the problem I am trying to solve for further context

Using jQuery or vanilla JS you will display each USER in a table. When the user selects a USER in the table, it will display all of the 'POSTS' that were created by that USER.

index.js

index.html

table

data.json

Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
Cespinoza
  • 11
  • 1
  • 3
    Please include the code directly in your posts, rather than images, whose links can change or be removed. – mykaf Apr 14 '22 at 20:19
  • @Cespinoza ... Regarding the so far provided answers / approaches / solutions are there any questions left? – Peter Seliger May 02 '22 at 09:39

2 Answers2

0

Make use of event delegation together with Element.closest and the data-* attribute respectively its HTMLElement.dataset counterpart.

document
  .querySelector('tbody')
  .addEventListener('click', ({ target }) => {

    const currentRow = target.closest('tr');
    const userId = currentRow.dataset.id;

    console.clear();
    console.log('userId: ', userId);
  });
body {
  margin: 0 0 0 2px;
}
table {
  border-collapse: collapse;
}
thead th {
  color: #fff;
  font-weight: bolder;
  background-color: #009577;
}
th, td {
  padding: 4px 10px 6px 10px;
  color: #0a0a0a;
}
tbody tr:nth-child(even) {
  background-color: #eee;
}
tbody tr:hover {
  outline: 2px dotted orange;
}
tbody tr {
  cursor: pointer;
}



tbody tr:nth-child(even) { background-color: #eee; }
tbody tr:hover { outline: 2px dotted orange; }
<table>
  <thead>
    <tr>
      <th>Id</th>
      <th>Name</th>
      <th>Username</th>
      <th>Email</th>
    </tr>
  </thead>
  <tbody>
    <tr data-id='1'>
      <td>1</td>
      <td>Leanne Graham</td>
      <td>Bret</td>
      <td>Sincere@april.biz</td>
    </tr>
    <tr data-id='2'>
      <td>2</td>
      <td>Ervin Howell</td>
      <td>Antonette</td>
      <td>Shanna@melissa.tv</td>
    </tr>
    <tr data-id='3'>
      <td>3</td>
      <td>Clementine Bauch</td>
      <td>Samantha</td>
      <td>Nathan@yesenia.net</td>
    </tr>
    <tr data-id='4'>
      <td>4</td>
      <td>Patricia Lebsack</td>
      <td>Karianne</td>
      <td>Julianne.OConner@kory.org</td>
    </tr>
    <tr data-id='5'>
      <td>5</td>
      <td>Chelsey Dietrich</td>
      <td>Kamren</td>
      <td>Lucio_Hettinger@annie.ca</td>
    </tr>
  </tbody>
</table>

A vanilla based implementation of a component-like approach which is partially configurable via data-* attributes then possibly might look like the next provided example code ...

function emptyElementNode(node) {
  [...node.childNodes].forEach(child => child.remove());
}
function clearTableContent(root) {
  [
    ...root.querySelectorAll('thead'), 
    ...root.querySelectorAll('tbody'),

  ].forEach(child => child.remove());
}

function createTableHead(headerContentList) {
  const elmThead = document.createElement('thead');
  const elmTr = headerContentList
    .reduce((root, content) => {

      const elmTh = document.createElement('th');
      elmTh.textContent = content;

      root.appendChild(elmTh);

      return root;      
    }, document.createElement('tr'));
  
  elmThead.appendChild(elmTr);
  return elmThead;
}
function createTableBody(rowContentKeyList, userList) {
  return userList
    .reduce((elmTbody, userItem) => {

      const elmTr = rowContentKeyList
        .reduce((root, key) => {

          const elmTd = document.createElement('td');
          elmTd.textContent = userItem[key];

          root.appendChild(elmTd);

          return root;
        }, document.createElement('tr'));

      elmTr.dataset.id = userItem.id;
      elmTbody.appendChild(elmTr);

      return elmTbody;
    }, document.createElement('tbody'));
}
function createAndRenderPostItem(root, { title, body }) {
  const elmDt = document.createElement('dt');
  const elmDd = document.createElement('dd');

  elmDt.textContent = title;
  elmDd.textContent = body;

  root.appendChild(elmDt);
  root.appendChild(elmDd);

  return root;
}

function updateSelectedStates(selectedRow) {
  [...selectedRow.parentNode.children]
    .forEach(rowNode =>
      rowNode.classList.remove('selected')
    );
  selectedRow.classList.add('selected');
}

function handleUserPostsRequestFromBoundData({ target }) {
  const { postsRoot, requestUrl, placeholder } = this;

  const currentRow = target.closest('tr');
  const userId = currentRow?.dataset?.id;

  if (userId) {
    createListOfUserPosts({
      postsRoot,
      url: requestUrl.replace(placeholder, userId)
    });
    updateSelectedStates(currentRow);
  }
}

async function createListOfUserPosts({ postsRoot, url }) {
  emptyElementNode(postsRoot);

  if (postsRoot && url) {
    const response = await fetch(url);
    const postList = await response.json();

    postList.reduce(createAndRenderPostItem, postsRoot);
  }
}
async function createListOfUsers({ usersRoot, postsRoot }) {
  const usersRequestUrl = usersRoot.dataset.request;

  const userPostsRequestUrl = postsRoot.dataset.request;
  const userPostsPlaceholder = postsRoot.dataset.placeholder;

  const response = await fetch(usersRequestUrl);
  const userList = await response.json();

  if (userList.length >= 1) {
    const displayConfig = JSON.parse(
      usersRoot.dataset.display ?? '{}'
    );
    const headerContentList = Object.values(displayConfig);
    const rowContentKeyList = Object.keys(displayConfig);

    emptyElementNode(postsRoot);
    clearTableContent(usersRoot);

    usersRoot.appendChild(
      createTableHead(headerContentList)
    );
    usersRoot.appendChild(
      createTableBody(rowContentKeyList, userList)
    );
    usersRoot.addEventListener(
      'click',
      handleUserPostsRequestFromBoundData
        .bind({
          postsRoot,
          requestUrl: userPostsRequestUrl,
          placeholder: userPostsPlaceholder,
        })
    );
  }  
}

function initializeUserPostsComponent(root) {
  const usersRoot = root.querySelector('[data-users]');
  const postsRoot = root.querySelector('[data-posts]');

  createListOfUsers({ usersRoot, postsRoot });
}
document
  .querySelectorAll('[data-user-posts]')
  .forEach(initializeUserPostsComponent);
body { margin: 0 0 0 2px; font-size: .8em; }
table { border-collapse: collapse; }
table caption { text-align: left; padding: 3px; }
thead th { color: #fff; font-weight: bolder; background-color: #009577; }
th, td { padding: 3px 5px; color: #0a0a0a; }
tbody tr:nth-child(even) { background-color: #eee; }
tbody tr:hover { outline: 2px dotted orange; }
tbody tr.selected { background-color: rgb(255 204 0 / 18%); }
tbody tr { cursor: pointer; }
[data-user-posts]::after { clear: both; display: inline-block; content: ''; }
.user-overview { float: left; width: 63%; }
.user-posts { float: right; width: 36%; }
.user-posts h3 { margin: 0; padding: 4px 8px; font-size: inherit; font-weight: normal; }
<article data-user-posts>
  <table 
    data-users
    data-request="https://jsonplaceholder.typicode.com/users"
    data-display='{"id":"Id","name":"Name","username":"Username","email":"Email"}'
    class="user-overview"
  >
    <caption>Select a user to view posts</caption>
  </table>
  <div class="user-posts">
    <h3>Posts:</h3>
    <dl
      data-posts
      data-request="https://jsonplaceholder.typicode.com/users/:userId/posts"
      data-placeholder=":userId"
    >
    </dl>
  </div>
<article>
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
-1

To add a click event handler to a table row with JavaScript, we can loop through each row and set the onclick property of each row to an event handler.

For instance, we add a table by writing:

<table>
  <tbody>
    <tr>
      <td>foo</td>
      <td>bar</td>
    </tr>
    <tr>
      <td>baz</td>
      <td>qux</td>
    </tr>
  </tbody>
</table>

Then we write:

const createClickHandler = (row) => {
  return () => {
    const [cell] = row.getElementsByTagName("td");
    const id = cell.innerHTML;
    console.log(id);
  };
};

const table = document.querySelector("table");
for (const currentRow of table.rows) {
  currentRow.onclick = createClickHandler(currentRow);
}

to add event handlers to each row.

Reference : https://thewebdev.info/2021/09/12/how-to-add-an-click-event-handler-to-a-table-row-with-javascript/#:~:text=Row%20with%20JavaScript-,To%20add%20an%20click%20event%20handler%20to%20a%20table%20row,row%20to%20an%20event%20handler.&text=to%20add%20event%20handlers%20toe,table%20row%20as%20a%20parameter.