Home > Blockchain >  How can I check for a value, empty value and !value in a conditional statement?
How can I check for a value, empty value and !value in a conditional statement?

Time:09-27

I have a select field with the list of countries. And I want to show something ONLY for the US selection, and something else for !US selections. But I also want it to do something else when NOTHING is selected. The problem is, Nothing is also inclusive in a non-US selection.

P.S. I know my code is a bit verbose, if you want to offer a smaller solution, I'll be grateful. But I'm ok with it just working

Here's the code

var selectedCountry, selectAutograph

$('.country, .autograph').on('change', function() {

  selectedCountry = $('.country').find('option:selected').val();
  selectAutograph = $('.autograph').is(":checked")

  if (selectedCountry === "United States" && !selectAutograph) {
    console.log("Show US Only");
    $(".us").show();
    $(".int, .intauto, .usauto").hide();

  } else if (selectedCountry !== "United States" && !selectAutograph) {
    console.log("Show Int Only");
    $(".int").show();
    $(".us, .intauto, .usauto").hide();

  } else if (selectedCountry === "United States" && selectAutograph) {
    console.log("Show US and Autograph");
    $(".usauto").show();
    $(".intauto, .us, .int").hide();

  } else if (selectedCountry !== "United States" && selectAutograph) {
    console.log("Show Int and Autograph");
    $(".intauto").show();
    $(".usauto, .us, .int").hide();

  } else {
    console.log("Show Nothing");
    $(".intauto, .usauto, .us, .int").hide();
  }
});
.hide {
  display: none;
}
<form id="order-form" method="post" role="form">
  <select  name="country" id="country">
    <option value="Select Country">Select Country</option>
    <option value="United States">United States</option>
    <option value="Canada">Canada</option>
    <option value="United Kingdom">United Kingdom</option>
    <!-- ... -->
    <option value="Zimbabwe">Zimbabwe</option>
  </select>

  <div >
    <input  type="checkbox" value="" id="autograph" name="autograph">
    <label > Add autograph </label>
  </div>
</form>

<div>
  <div >
    US shipping
  </div>

  <div >
    International shipping
  </div>

  <div >
    US shipping   add autograph
  </div>

  <div >
    International shipping   add autograph
  </div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Here's a JSFiddle as well. Thanks in advanced

CodePudding user response:

The else will never run because the Select Country country option will run in the selectedCountry !== "United States" && !selectAutograph or selectedCountry !== "United States" && selectAutograph condition, Also you can simplify the code, by adding data atttibutes.

Please check this.

var selectedCountry, selectAutograph
 var country = {
   "Select Country": "non",
   "United States": "us",
 }
      
      $('.country, .autograph').on('change', function() {   

        selectedCountry = $('.country').find('option:selected').val();     
        selectAutograph = $('.autograph').is(":checked")
        $('[data-autograpgh], [data-country="non-us"], [data-country="us"]').hide()
        if(country[selectedCountry] === "us" && !selectAutograph) {
          $('[data-country="us"]:not([data-autograpgh])').show()
        } else if(!country[selectedCountry] && !selectAutograph)   {
          $('[data-country="non-us"]:not([data-autograpgh])').show()
        } else if(country[selectedCountry] === "us" && selectAutograph)   {
          $('[data-country="us"][data-autograpgh]').show()
        } else if(!country[selectedCountry] && selectAutograph)   {
          $('[data-country="non-us"][data-autograpgh]').show()
        }
                        
      });
.hide {
  display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form  id="order-form" method="post" role="form">
      <select    name="country"  id="country" required="">
        <option value="Select Country">Select Country</option>
        <option value="United States">United States</option>
        <option value="Canada">Canada</option>
        <option value="United Kingdom">United Kingdom</option>
        <option value="Zimbabwe">Zimbabwe</option>
      </select>

      <div >
        <input  type="checkbox" value="" id="autograph" name="autograph">
        <label > Add autograph </label>
      </div>
    </form>

    <div>
      <div  data-country="us">
        US shipping                   
      </div>

      <div  data-country="non-us">
        International shipping                                    
      </div> 

      <div  data-country="us" data-autograpgh>
        US shipping   add autograph
      </div>  

      <div  data-country="non-us" data-autograpgh>
        International shipping   add autograph
      </div>
    </div>

CodePudding user response:

While you've already accepted an answer, I wanted to offer an alternative approach:

// creating an Object in which we can access properties
// of individual countries; the key of each object is
// the value from the <select> element:
const countries = {
  us: {
    country: 'United States',
    international: false,
  },
  canada: {
    country: 'Canada',
    international: true,
  },
  uk: {
    country: 'United Kingdom',
    international: true,
  },
  zimbabwe: {
    country: 'Zimbabwe',
    international: true,
  }
};

// caching the elements:
let countrySelect = $('.country'),
  autograph = $('.autograph');

// binding the anonymous function of the on() method as the event-handler
// for the 'change' event:
$('.country, .autograph').on('change', function() {
  // hiding the children of the '.details' element:
  $('.details > *').hide();

  // retrieving the selected <option> element:
  let selectedOption = countrySelect.find(':selected');

  // HTMLOptionElement.defaultSelected is a Boolean property which is
  // true if the <option> had the selected attribute on page-load, or
  // false if the <option> did not have the 'selected' attribute on
  // page-load:
  if (selectedOption.prop('defaultSelected')) {
    // all elements are now hidden by default in the function,
    // so no action taken except for logging a statement to the
    // console:
    console.log("No country selected.");
  } else {
    // here we retrieve the value of the selected <option>:
    let value = selectedOption.val(),
      // using destructuring to declare the variables that
      // are also property-names from the countries[value]
      // property-value:
      {
        country,
        international
      } = countries[value],
      // determining whether the checkbox is checked, the
      // .is() method returns a Boolean reflecting that
      // the collection matches the supplied selector:
      withAutograph = autograph.is(':checked'),

      // here we create the CSS selector, using a template-literal String;
      // the first conditional operator tests whether the 'international'
      // variable is true; if yes this returns the string 'int', otherwise
      // returning the string 'us'
      // the second conditional tests to see if 'withAutograph' is true,
      // if so returning the string 'auto', othewise an empty string:
      selector = `.${international ? 'int' : 'us'}${withAutograph ? 'auto' : ''}`;

    // we then use that selector, and call the show() method:
    $(selector).show();
  }
});
.hide {
  display: none;
}
<form id="order-form" method="post" role="form" action="#">
  <select  name="country" id="country">
    <option value="Select Country" selected>Select Country</option>
    <!--
        Here I've changed the value to a lower-case single string, in
        order to reduce the chance of a mis-typed white-space character
        causing trouble elsewhere, and use an abbreviation where
        possible/obvious to do so:
    -->
    <option value="us">United States</option>
    <option value="canada">Canada</option>
    <option value="uk">United Kingdom</option>
    <option value="zimbabwe">Zimbabwe</option>
  </select>

  <div >
    <input  type="checkbox" value="" id="autograph" name="autograph">
    <label > Add autograph </label>
  </div>
</form>

<!--
    This element was given a class-name ('details') in order to easily hide
    the contents without having to refer to them individually:
-->
<div >
  <div >
    US shipping
  </div>

  <div >
    International shipping
  </div>

  <div >
    US shipping   add autograph
  </div>

  <div >
    International shipping   add autograph
  </div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

JS Fiddle demo.

This is, of course, perfectly possible with plain JavaScript:

// caching a reference to the document, along with some utility
// helper functions to simplify life (and reduce typing):
const D = document,
  // here we define an alias for querySelector(), which will use
  // either document.querySelector() or element.querySelector()
  // depending on whether a context is passed to the function;
  // if no context is passed document.querySelector() will be
  // used, otherwise with a context that Element will be used:
  get = (sel, context = D) => context.querySelector(sel),
  // as above, but here we call querySelectorAll() and return
  // the retrieved NodeList as an Array of Nodes in order to
  // utilise Array methods:
  getAll = (sel, context = D) => [...context.querySelectorAll(sel)],
  // creating an Object in which we can access properties
  // of individual countries; the key of each object is
  // the value from the <select> element:
  countries = {
    us: {
      country: 'United States',
      international: false,
    },
    canada: {
      country: 'Canada',
      international: true,
    },
    uk: {
      country: 'United Kingdom',
      international: true,
    },
    zimbabwe: {
      country: 'Zimbabwe',
      international: true,
    }
  };

// caching the elements:
let countrySelect = get('.country'),
  autograph = get('.autograph'),
  // the change-handling function:
  changeHandler = (evt) => {
    // hiding the children of the '.details' element:
    getAll('.details > *').forEach(
      (el) => el.classList.add('hide')
    );

    // retrieving the selected <option> element, with CSS
    // the selected <option> matches the :checked pseudo-
    // class, and we're looking within the context of the
    // countrySelect <select> element:
    let selectedOption = get(':checked', countrySelect);

    // HTMLOptionElement.defaultSelected is a Boolean property which is
    // true if the <option> had the selected attribute on page-load, or
    // false if the <option> did not have the 'selected' attribute on
    // page-load:
    if (selectedOption.defaultSelected) {
      // all elements are now hidden by default in the function,
      // so no action taken except for logging a statement to the
      // console:
      console.log("No country selected.");
    } else {
      // here we retrieve the value of the selected <option>:
      let value = selectedOption.value,
        // using destructuring to declare the variables that
        // are also property-names from the countries[value]
        // property-value:
        {
          country,
          international
        } = countries[value],
        // determining whether the checkbox is checked, the
        // property itself returns a Boolean indicating whether
        // the node is checked (true) or unchecked (false):
        withAutograph = autograph.checked,

        // here we create the CSS selector, using a template-literal String;
        // the first conditional operator tests whether the 'international'
        // variable is true; if yes this returns the string 'int', otherwise
        // returning the string 'us'
        // the second conditional tests to see if 'withAutograph' is true,
        // if so returning the string 'auto', othewise an empty string:
        selector = `.${international ? 'int' : 'us'}${withAutograph ? 'auto' : ''}`;

      // here we retreive all elements matching the selector, and then use
      // Array.prototype.forEach() to iterate over that Array of Nodes with
      // an Arrow function:
      getAll(selector).forEach(
        // here we pass in a reference to the current Node of the Array,
        // and we remove the 'hide' class-name from the Element's classList:
        (el) => el.classList.remove('hide')
      );

    }
  };

// using Array.prototype.forEach() to iterate over the Array-literal which
// contains both interactive elements with which the user interacts:
[countrySelect, autograph].forEach(
  // binding the changeHandler function as the event-handler for the 'change' event:
  (el) => el.addEventListener('change', changeHandler)
);
.hide {
  display: none;
}
<form id="order-form" method="post" role="form" action="#">
  <select  name="country" id="country">
    <option value="Select Country" selected>Select Country</option>
    <!--
        Here I've changed the value to a lower-case single string, in
        order to reduce the chance of a mis-typed white-space character
        causing trouble elsewhere, and use an abbreviation where
        possible/obvious to do so:
    -->
    <option value="us">United States</option>
    <option value="canada">Canada</option>
    <option value="uk">United Kingdom</option>
    <option value="zimbabwe">Zimbabwe</option>
  </select>

  <div >
    <input  type="checkbox" value="" id="autograph" name="autograph">
    <label > Add autograph </label>
  </div>
</form>

<!--
    This element was given a class-name ('details') in order to easily hide
    the contents without having to refer to them individually:
-->
<div >
  <div >
    US shipping
  </div>

  <div >
    International shipping
  </div>

  <div >
    US shipping   add autograph
  </div>

  <div >
    International shipping   add autograph
  </div>
</div>

References:

  • Related