skip to Main Content

Suppose, I don’t know for sure if there are checked authorities or not (but if they are present, I want them). If checked authorities are absent, I want jQuery to select authorities with no regard whether they are checked or not (in practice, it would mean retrieving the value of a hidden input). My idea of using JS’s "truthy"/"falsy" concept for handling this kind of situations was this:

    let user = {
        id: $(this).find('[name=id]').val(),
        username: $(this).find('[name=username]').val(),
        password: $(this).find('[name=password]').val(),
        name: $(this).find('[name=name]').val(),
        lastName: $(this).find('[name=lastName]').val(),
        department: $(this).find('[name=department]').val(),
        salary: $(this).find('[name=salary]').val(),
        age: $(this).find('[name=age]').val(),
        email: $(this).find('[name=email]').val(),
        enabledByte: $(this).find('[name=enabledByte]').val(),
        authorities: JSON.parse($(this).find('[name=authorities]:checked').val()) || 
                    JSON.parse($(this).find('[name=authorities]').val())
    };

However, it doesn’t work. Funnily enough, it does work in the code snippet below. Isn’t undefined, returned by val() in case of a failed match, falsy? Go figure! My best guess is that JSON.parse() throws an error when parsing an undefined instead of returning some falsy value, as I want it to. The method doesn’t accept "param OR param", does it?

How do you think I should provide that kind of fallbacks in my case (other than, of course, checking the falsiness of checked authorities separately which would be a bit too verbose for my liking)?

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
              integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
        <title>Admin Page</title>
    </head>
    <body>
    <div class="container">
        <div class="row mb-2">
            <ul class="nav nav-tabs">
                <li class="nav-item">
                    <a class="nav-link active" data-toggle="tab" href="#users-table">All Users</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" data-toggle="tab" href="#add-new-user">Add New User</a>
                </li>
            </ul>
       </div>
            <div class="row tab-content">
            <div id="users-table" class="tab-pane container active">
            <table class="table table-hover text-center">
                      <thead>
                            <tr>
                                <th scope="col">Name</th>
                                <th scope="col">Last name</th>
                                <th scope="col">Department</th>
                                <th scope="col">Email</th>
                            </tr>
                      </thead>
                      <tbody>
                            <tr>
                                <td>John</td>
                                <td>Doe</td>
                                <td>IT</td>
                                <td>[email protected]</td>
                            </tr>
                            <tr>
                                <td>Jane</td>
                                <td>Doe</td>
                                <td>HR</td>
                                <td>[email protected]</td>
                            </tr>
                     </tbody>
              </table>
            </div>
           <div id="add-new-user" class="tab-pane container">
              <h3>Fill in the forms</h3>
                              <form>
                                  <div class="form-group">
                                      <label for="name">Name: </label>
                                      <input id="name" name="name" type="text" class="form-control" required />
                                  </div>

                                  <div class="form-group">
                                      <label for="last-name">Last name: </label>
                                      <input id="last-name" name="last-name" type="text" class="form-control" required />
                                  </div>

                                  <div class="form-group">
                                      <label for="department">Department: </label>
                                      <select id="department" name="department" class="form-control">
                                          <option value="IT">IT</option>
                                          <option value="HR">HR</option>
                                          <option value="accounting">Accounting</option>
                                      </select>
                                  </div>

                                  <div class="form-group">
                                      <label for="email">Email: </label>
                                      <input id="email" name="email" type="email" class="form-control" />
                                  </div>

                                  <input type="submit" class="btn btn-primary d-flex ml-auto" value="Submit" />
                              </form>
                  </div>
              </div>
          </div>
    </div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
    <script>
$(document).ready(function () {
$('form').on('submit', async function (event) {
    event.preventDefault();
    $('tbody').append(
    `<tr>
         <td>
             ${$(this).find('[name=name]').val()}
         </td>
         <td>
             ${$(this).find('[name=last-name]').val()}
         </td>
         <td>
             ${$(this).find('[name=department]').val()}
         </td>
         <td>
             ${$(this).find('[name=email]').val() || 'N/A'}
         </td>
     </tr>`
    );
            const submitButton = $(this).find('[type=submit]');
            const form = $(this);

            submitButton.removeClass('btn-primary')
                .addClass('btn-success')
                .attr('value', 'User added!')
                .attr('type', 'button')
                .click(() => $('[href="#users-table"]').tab('show'));

            setTimeout(function () {
                submitButton.removeClass('btn-success')
                    .addClass('btn-primary')
                    .attr('value', 'Submit')
                    .attr('type', 'submit')
                    .off('click');
                form.trigger('reset');
            }, 8000);
});
});
    </script>
    </body>
    </html>

2

Answers


  1. You have a few options depending on your use case:

    1. You can combine the JSON.parses like this. This will make it fall back to the other string before it parses, so it won’t error if the first value is undefined. However, if both values are undefined or one is invalid JSON, this will error.
    JSON.parse($(this).find('[name=authorities]:checked').val()) || $(this).find('[name=authorities]').val());
    
    1. If you know that the values will either be valid JSON or undefined, you can fall back to null. null is a valid JSON value and can be parsed. However, this will still error if either value is invalid JSON.
    JSON.parse($(this).find('[name=authorities]:checked').val()) || $(this).find('[name=authorities]').val() || null);
    
    1. If there’s a chance that either value will be invalid JSON, you can surround it in a try/catch block. This way, even if it is invalid, it will not throw. This is the safest option and will never error.
    // Helper to make it easier to do this inline
    function safeJsonParse(string) {
      try {
        return JSON.parse(string);
      } catch {
        // JSON is invalid. Will implicitly return undefined.
      }
    }
    
    safeJsonParse($(this).find('[name=authorities]:checked').val()) || safeJsonParse($(this).find('[name=authorities]').val())
    
    Login or Signup to reply.
  2. The problem is that .val() returns undefined if the selector doesn’t find any matches, and JSON.parse(undefined) raises an exception.

    Do the fallback inside the argument list of JSON.parse(), so you’ll parse whichever value you fetch successfully.

    authorities: JSON.parse($(this).find('[name=authorities]:checked').val() || 
                            $(this).find('[name=authorities]:first').val())
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search