1

I created an object simulating the JSON return I get from the database.

Problem:

  • I can't find invoices for the drop-down list element of the selected contract when loading a function.
  • I cannot list the invoices when changing an option in the<select>.

Example

let lblContract = document.querySelector('#contracts');
let UlInvoices = document.querySelector('#ul-invoices');

let contractInAttendance = 1;

const objectContract = {
  id: 1,
  nome: 'wagner',
  contracts: [{
      id: 1,
      contract: '123456',
      batches: [{
          id: 1,
          contract_id: 1,
          batch: '1',
          invoices: [{
            value: 10,
            batch_id: 1,
          }]
        },
        {
          id: 2,
          contract_id: 1,
          batch: '2',
          invoices: [{
            value: 10,
            batch_id: 2,
          }]
        }
      ]
    },
    {
      id: 2,
      contract: '246789',
      batches: [{
        id: 3,
        contract_id: 2,
        batch: '1',
        invoices: [{
          value: 20,
          batch_id: 3,
        }]
      }]
    }
  ]
}

const revelling = (function() {

  function privateInit() {
    const contracts = objectContract.contracts;
    let contractFilteredById = contracts.filter(contract => contract.id === contractInAttendance);

    for (const contract of contracts) {
      const selectedContract = contract.id === contractFilteredById[0].id ? 'in-attendance' : '';

      let htmlForBatchsOptions = contract.batches.map(batch => `<option value=${batch.id}>${batch.batch}</option>`).join('');
      lblContract.innerHTML +=
        `<div class="contract-${selectedContract}" style="display: flex;">
                            <div id="contract-${contract.contract}" data-contract="${contract.id}" class="loren">
                                <span>${contract.contract}</span>
                            </div>
                            <div class="ipsulum" style="margin-left: 5px;">
                                <select class="sel-batch">
                                    ${htmlForBatchsOptions}
                                </select>
                            </div>
                        </div>`;

      const batchOption = lblContract.querySelector('select.sel-batch');
      batchOption.addEventListener('change', getInvoices);
      //batchOption.value = 2;
    }
  }

  function getInvoices() {
    const batchValue = event.target.value
    console.log(batchValue);
    //console.log(this.value);
  }

  return {
    init: privateInit
  }

})();
revelling.init();
<label id="contracts"></label>
<ul id="ul-invoices"></ul>

Update:

I did it, but I didn't find it very pleasant and there is certainly a simpler way to do it. I would like another opinion.

let lblContract = document.querySelector('#contracts');
let UlInvoices = document.querySelector('#ul-invoices');

let contractInAttendance = 1;

const objectContract = {
    id: 1,
    nome: 'wagner',
    contracts: [{
            id: 1,
            contract: '123456',
            batches: [{
                    id: 1,
                    contract_id: 1,
                    batch: '1',
                    invoices: [{
                            id: 1,
                            batch_id: 1,
                            invoice: 1,
                            due: '2019-01-01',
                            value: 10
                        },
                        {
                            id: 2,
                            batch_id: 1,
                            invoice: 2,
                            due: '2019-02-01',
                            value: 10
                        }
                    ]
                },
                {
                    id: 2,
                    contract_id: 1,
                    batch: '2',
                    invoices: [{
                        id: 3,
                        batch_id: 2,
                        invoice: 3,
                        due: '2019-03-01',
                        value: 10
                    }, ]
                }
            ]
        },
        {
            id: 2,
            contract: '654321',
            batches: [{
                id: 3,
                contract_id: 2,
                batch: '1',
                invoices: [{
                        id: 4,
                        batch_id: 3,
                        invoice: 1,
                        due: '2019-01-01',
                        value: 20
                    },
                    {
                        id: 5,
                        batch_id: 3,
                        invoice: 2,
                        due: '2019-02-01',
                        value: 20
                    }
                ]
            }]
        }
    ]
}

const revelling = (function() {
    'use strict';

    function privateInit() {
        const contracts = objectContract.contracts;
        let contractFilteredById = contracts.filter(contract => contract.id === contractInAttendance);

        let item = '';
        for (const contract of contracts) {
            const selectedContract = contract.id === contractFilteredById[0].id ? '-in-attendance' : '';
            lblContract.innerHTML +=
                `<div class="contract${selectedContract}" style="display: flex;">
                        <div id="contract-${contract.contract}" data-contract="${contract.id}" class="loren">
                            <span>${contract.contract}</span>
                        </div>
                        <div class="ipsulum" style="margin-left: 5px;">
                            <select class="sel-batch">
                                ${contract.batches.map(batch => `<option value=${batch.id}>${batch.batch}</option>`).join('')}
                            </select>
                        </div>
                        <span></span>
                    </div>`;
        }

        let lblContractSelected = lblContract.querySelector('.contract-in-attendance');
        const batchOption = lblContractSelected.querySelector('select.sel-batch');
        let batchValue = batchOption.options[batchOption.selectedIndex].value;

        batchOption.addEventListener('change', getInvoices);

        function getInvoices(event = false) {
            if (event)
                batchValue = event.target.value

            const batches = contractFilteredById[0].batches;
            const batch = batches.filter(batch => batch.id == batchValue);
            const invoices = batch[0].invoices;

            const invoice = invoices.map(function(item, indice) {
                return `<tr>
                            <!--<td>${indice + 1}</td>-->
                            <td>${item.invoice}</td>
                            <td>${item.value}</td>
                            <td>${item.due}</td>
                            </tr>`;
            });
            document.querySelector('#tb-invoices tbody').innerHTML = invoice.join('');

        }
        getInvoices();
    }

    return {
        init: privateInit
    }

})();
revelling.init();
.contract-in-attendance > span {
     width: 8px;
     height: 8px;
     margin: 5px;
     background: #00b070;
     border-radius: 50%;
     display:inline-block;
}
<label id="contracts"></label>
<table id="tb-invoices" style="display:none-">
   <thead>
      <tr>
         <th>invoice</th>
         <th>value</th>
         <th>due</th>
      </tr>
   </thead>
   <tbody>
   </tbody>
</table>
Wagner Fillio
  • 395
  • 3
  • 19
  • Note that the line `revelling.init` at the end of the JavaScript does nothing. `privateInit()` is called a few lines up in `return { init: privateInit() }` If you want to expose it as a function, use `return { init: privateInit }` and use `revelling.init()` at the end. – Heretic Monkey Jul 09 '20 at 19:36
  • Does this answer your question? [How can I access and process nested objects, arrays or JSON?](https://stackoverflow.com/questions/11922383/how-can-i-access-and-process-nested-objects-arrays-or-json) – Heretic Monkey Jul 09 '20 at 19:39
  • Hi @HereticMonkey, My problem may even be accessing the property of an object, however, I am inside a loop and need to display all contracts, contract lots and display only the invoices for the selected contract lot and, if I change the lot, load the invoices – Wagner Fillio Jul 09 '20 at 20:01
  • So... using the answers to the question I posted, you should be able to access the correct `invoices` property with `objectContract`. – Heretic Monkey Jul 09 '20 at 20:04
  • But when you select something from the `select`, `getInvoices` is called, and you're not in a loop. – Heretic Monkey Jul 09 '20 at 20:05
  • @HereticMonkey, I think my biggest doubt is; when should I access the invoices and what parameter should I enter to obtain the invoices corresponding to the batch and how can I send the invoices to the getInvoices function – Wagner Fillio Jul 09 '20 at 20:25
  • This is a problem for me – Wagner Fillio Jul 09 '20 at 20:26

1 Answers1

0

You're probably better of separating the rendering portion of the UI to a separate function, and the retrieval and event of data in another.

This is also probably an over complicated version of what you're trying to accomplish, but I do hope it helps in some way.

Click Run code snippet below.

// Constant
const OBJECT_CONTRACT = {
  id: 1,
  nome: 'wagner',
  contracts: [{
      id: 1,
      contract: '123456',
      batches: [{
          id: 1,
          contract_id: 1,
          batch: '1',
          invoices: [{
            value: 10,
            batch_id: 1,
          }]
        },
        {
          id: 2,
          contract_id: 1,
          batch: '2',
          invoices: [{
            value: 10,
            batch_id: 2,
          }]
        }
      ]
    },
    {
      id: 2,
      contract: '246789',
      batches: [{
        id: 3,
        contract_id: 2,
        batch: '1',
        invoices: [{
          value: 20,
          batch_id: 3,
        }]
      }]
    }
  ]
};

let CONTRACT_SELECTED = null;
let CONTRACT_LOT_SELECTED = null;

// EVENT HANDLERS
const onChange = (event, fieldValue, dataSelected, callback) => {
  if (dataSelected === 'CONTRACT_SELECTED') {
    CONTRACT_SELECTED = parseInt(event.target.value);
    CONTRACT_LOT_SELECTED = null;
  }
  if (dataSelected === 'CONTRACT_LOT_SELECTED') CONTRACT_LOT_SELECTED = parseInt(event.target.value);
  
  // render anything else
  if (callback) {
      callback()
  }
}

// VIEWS
/**
* newData = Array
* el = DOM Element
*/
const renderSelected = (label, newData, el, fieldValue, fieldDisplay, dataSelected, callback) => {
  // reset
  el.innerHTML = '';
  
  const div = document.createElement('div');
  const h3 = document.createElement('h3');
  h3.innerHTML = label;

  const select = document.createElement('select');
  select.addEventListener('change', (event) => onChange(event, fieldValue, dataSelected, callback));
  
  const defaultOption = document.createElement('option');
  defaultOption.setAttribute('value', null);
  defaultOption.innerHTML = `Select ${label}`;
  defaultOption.setAttribute('disabled', 'disabled');
  defaultOption.setAttribute('selected', 'selected');
  select.append(defaultOption);
  
  for (let i = 0; i < newData.length; i++) {
    const option = document.createElement('option');
    option.setAttribute('value', newData[i][fieldValue]);
    option.innerHTML = newData[i][fieldDisplay];
    select.append(option);
  }
  div.append(h3);
  div.append(select)
  el.append(div);
}

const renderInvoices = (label, data, el) => {
el.innerHTML = '';
  
  if (data && data.length > 0) {
    const div = document.createElement('div');
    const h3 = document.createElement('h3');
    h3.innerHTML = label;
    
    const ul = document.createElement('ul');
    for (let i = 0; i < data.length; i++) {
      const li = document.createElement('li');
      li.innerHTML = `Batch ID - ${data[i].batch_id} - Value ${data[i].value}`;
      ul.append(li);
    }
    
    div.append(h3);
    div.append(ul);
    el.append(div);
    }
}

// LOGIC
// For rendering logic to pass down arrays
const getInvoices = () => {
  const invoices = OBJECT_CONTRACT.contracts.find(i => i.id === CONTRACT_SELECTED).batches.find(i => i.id === CONTRACT_LOT_SELECTED).invoices;
  
  renderInvoices('Invoices', invoices, document.querySelector('#invoices'));
}

const getBatches = () => {
  renderInvoices('Invoices', null, document.querySelector('#invoices'));
  
  renderSelected('Batches', OBJECT_CONTRACT.contracts.find(i => i.id === CONTRACT_SELECTED).batches,     document.querySelector('#batches'), 'id', 'batch', 'CONTRACT_LOT_SELECTED', getInvoices);
}

const getContracts = () => {
  renderSelected('Contracts', OBJECT_CONTRACT.contracts,     document.querySelector('#contracts'), 'id', 'contract', 'CONTRACT_SELECTED', getBatches);
};


// Init
window.addEventListener('load', () => {
  getContracts();
});
body {
  padding: 10px;
  font-family: Arial, sans-serif;
}

h1 {
  font-size: 18px;
}
<div id="root">
  <div id="contracts"></div>
  <div id="batches"></div>
  <div id="invoices"></div>
<div>
codingwithmanny
  • 1,126
  • 8
  • 20