0

A dropdown component is rendered twice adjacently.

When an item from a dropdown is selected, the entire dropdown component is pushed down.

I am not sure why this issue is occuring. (I am guessing this could be due to lack of space between the 2 dropdowns).

Don't know how to resolve this issue.

I have posted the code below.

function Dropdown() {
     this.id = '';
     this.items = [];
     
     this.settings = {
         isRendered: false,
      isListOpen: false
     };
     
     this.init = function(componentId) {
           this.id = componentId;
              this.cacheDOM();           
     };
     
     this.cacheDOM = function() {
                this.$el = $('#' + this.id);
      
                if (this.settings.isRendered)
                {
                    this.$input = this.$el.find('input');
           this.$dropbox = this.$el.find('div');
                    this.$dropdownicon = this.$el.find('span:first');
           this.$ul = this.$el.find('ul');
           this.$li = this.$ul.find('li');
                }
      
                this.template = `<div id='`+ this.id +`'>
                                              <div class='dropbox'><input /><span class='material-icons'>expand_more</span></div>
                                                       <ul style='display: none'>
                                                           {{#items}}
                                                           <li>{{.}}</li>
                                                           {{/items}}
                                              </ul>
                                         </div>`;
     };
     
     this.populateItems = function(items) {
                    this.items = items;
                    this.render();
     };
     
     this.applyStyles = function() {
      
       var elStyle = {
       'display': 'inline-block',
       'position': 'relative',
       'padding': '0',
       'margin': '0'
       };
       
       var dropboxStyle = {
        'display' : 'inline-flex',
        'border' : '1px solid #9DD9D2'
       };
       
       var inputStyle = {
        'font': 'inherit',
        'padding': '3px',
        'border': 'none'
       };
      
       var inputFocusStyle = {
        'border': 'none',
        'outline': 'none'
       };
      
      var dropdownIconStyle = {
         'background-color': '',
            'color': '#17BEBB'
      };
      
      var dropdownIconHoverStyle = {
        'cursor': 'default',
        'background-color': '#9DD9D2',
                             'color': 'white'
      };
      
      
      
                        this.$el.css(elStyle);
         this.$dropbox.css(dropboxStyle);
      this.$input.css(inputStyle);
      this.$input.on('focus', function() {
       $(this).css(inputFocusStyle);
      });
      this.$dropdownicon
         .css(dropdownIconStyle)
      .on('mouseenter', function() {
       $(this).css(dropdownIconHoverStyle);
      })
      .on('mouseleave', function() {
       $(this).css(dropdownIconStyle);
      });
     };
     
     this.bindEvents = function() {
      this.$dropdownicon.on('click', this.toggleList.bind(this));
      this.$li.on('mouseenter', this.toggleHoverItem.bind(this)).on('mouseleave', this.toggleHoverItem.bind(this));
      this.$li.on('click', this.itemClickHandler.bind(this));
     };
     
     this.itemClickHandler = function(event) {
      var itemSelected = $(event.target).closest('li').text();
      this.settings.isListOpen = !this.settings.isListOpen;
      this.$ul.css('display', 'none');      
      this.$input.val(itemSelected);
     }
     
     this.toggleHoverItem = function(event) {
      
      var itemMouseEnterStyle = {
       'background-color': '#9DD9D2',
       'color': 'white'
      }
      
      var itemMouseLeaveStyle = {
       'background-color': 'white',
       'color': 'black'
      }
      
      var backgroundColor = $(event.target).closest('li').css( "background-color" );
      
      if(backgroundColor == 'rgb(157, 217, 210)')
        $(event.target).closest('li').css(itemMouseLeaveStyle);
      else
                          $(event.target).closest('li').css(itemMouseEnterStyle);
     };
     
     this.toggleList = function() {
      var listOpenStyle = {
       'position': 'absolute',
       'display': 'block',
       'list-style-type': 'none',
       'border' : '1px solid #9DD9D2',
       'margin': '0',
       'padding': '2px 2px 2px 2px',
       'left': '0',
       'right': '0'
      }
      
      var listClosedStyle = {
       'display': 'none'
      }
      
      this.settings.isListOpen = !this.settings.isListOpen;
      
      if(this.settings.isListOpen)
         this.$ul.css(listOpenStyle);
      else
         this.$ul.css(listClosedStyle);
     };
     
     this.render = function() {
           var data = {items: this.items};
           this.$el.replaceWith(Mustache.render(this.template, data));
           this.settings.isRendered = true;
           this.cacheDOM();
           this.applyStyles();
           this.bindEvents();
     };
     
    };

   var dropdown = new Dropdown();
    dropdown.init('city');
    dropdown.populateItems(['Munich', 'Oslo', 'Havana']);
    dropdown.render();
   
   var dropdown2 = new Dropdown();
    dropdown2.init('city2');
    dropdown2.populateItems(['Los Angeles', 'Miami', 'Edinburg']);
    dropdown2.render();
  
 html, body {
                height: 100%;
                width: 100%;
                overflow: hidden;
                font-size: 1em;
                font-family: 'Lato', sans-serif;
            }
<!DOCTYPE html>
<html>
 <head>
 </head>
 <body>
  
  <span id='city'></span>
  <span id='city2'></span>
  
          <script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>

        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.js"></script>
        <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
        <link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet">

 </body>
</html>
vrn
  • 139
  • 2
  • 16

2 Answers2

0

Try adding vertical-align:middle; to the div with id 'city' and 'city2'

function Dropdown() {
     this.id = '';
     this.items = [];
     
     this.settings = {
         isRendered: false,
      isListOpen: false
     };
     
     this.init = function(componentId) {
           this.id = componentId;
              this.cacheDOM();           
     };
     
     this.cacheDOM = function() {
                this.$el = $('#' + this.id);
      
                if (this.settings.isRendered)
                {
                    this.$input = this.$el.find('input');
           this.$dropbox = this.$el.find('div');
                    this.$dropdownicon = this.$el.find('span:first');
           this.$ul = this.$el.find('ul');
           this.$li = this.$ul.find('li');
                }
      
                this.template = `<div id='`+ this.id +`'>
                                              <div class='dropbox'><input /><span class='material-icons'>expand_more</span></div>
                                                       <ul style='display: none'>
                                                           {{#items}}
                                                           <li>{{.}}</li>
                                                           {{/items}}
                                              </ul>
                                         </div>`;
     };
     
     this.populateItems = function(items) {
                    this.items = items;
                    this.render();
     };
     
     this.applyStyles = function() {
      
       var elStyle = {
       'display': 'inline-block',
       'position': 'relative',
       'padding': '0',
       'margin': '0','vertical-align':'middle',
       };
       
       var dropboxStyle = {
        'display' : 'inline-flex',
        'border' : '1px solid #9DD9D2'
       };
       
       var inputStyle = {
        'font': 'inherit',
        'padding': '3px',
        'border': 'none'
       };
      
       var inputFocusStyle = {
        'border': 'none',
        'outline': 'none'
       };
      
      var dropdownIconStyle = {
         'background-color': '',
            'color': '#17BEBB'
      };
      
      var dropdownIconHoverStyle = {
        'cursor': 'default',
        'background-color': '#9DD9D2',
                             'color': 'white'
      };
      
      
      
                        this.$el.css(elStyle);
         this.$dropbox.css(dropboxStyle);
      this.$input.css(inputStyle);
      this.$input.on('focus', function() {
       $(this).css(inputFocusStyle);
      });
      this.$dropdownicon
         .css(dropdownIconStyle)
      .on('mouseenter', function() {
       $(this).css(dropdownIconHoverStyle);
      })
      .on('mouseleave', function() {
       $(this).css(dropdownIconStyle);
      });
     };
     
     this.bindEvents = function() {
      this.$dropdownicon.on('click', this.toggleList.bind(this));
      this.$li.on('mouseenter', this.toggleHoverItem.bind(this)).on('mouseleave', this.toggleHoverItem.bind(this));
      this.$li.on('click', this.itemClickHandler.bind(this));
     };
     
     this.itemClickHandler = function(event) {
      var itemSelected = $(event.target).closest('li').text();
      this.settings.isListOpen = !this.settings.isListOpen;
      this.$ul.css('display', 'none');      
      this.$input.val(itemSelected);
     }
     
     this.toggleHoverItem = function(event) {
      
      var itemMouseEnterStyle = {
       'background-color': '#9DD9D2',
       'color': 'white'
      }
      
      var itemMouseLeaveStyle = {
       'background-color': 'white',
       'color': 'black'
      }
      
      var backgroundColor = $(event.target).closest('li').css( "background-color" );
      
      if(backgroundColor == 'rgb(157, 217, 210)')
        $(event.target).closest('li').css(itemMouseLeaveStyle);
      else
                          $(event.target).closest('li').css(itemMouseEnterStyle);
     };
     
     this.toggleList = function() {
      var listOpenStyle = {
       'position': 'absolute',
       'display': 'block',
       'list-style-type': 'none',
       'border' : '1px solid #9DD9D2',
       'margin': '0',
       'padding': '2px 2px 2px 2px',
       'left': '0',
       'right': '0'
      }
      
      var listClosedStyle = {
       'display': 'none'
      }
      
      this.settings.isListOpen = !this.settings.isListOpen;
      
      if(this.settings.isListOpen)
         this.$ul.css(listOpenStyle);
      else
         this.$ul.css(listClosedStyle);
     };
     
     this.render = function() {
           var data = {items: this.items};
           this.$el.replaceWith(Mustache.render(this.template, data));
           this.settings.isRendered = true;
           this.cacheDOM();
           this.applyStyles();
           this.bindEvents();
     };
     
    };

   var dropdown = new Dropdown();
    dropdown.init('city');
    dropdown.populateItems(['Munich', 'Oslo', 'Havana']);
    dropdown.render();
   
   var dropdown2 = new Dropdown();
    dropdown2.init('city2');
    dropdown2.populateItems(['Los Angeles', 'Miami', 'Edinburg']);
    dropdown2.render();
  
 html, body {
                height: 100%;
                width: 100%;
                overflow: hidden;
                font-size: 1em;
                font-family: 'Lato', sans-serif;
            }
<!DOCTYPE html>
<html>
 <head>
 </head>
 <body>
  
  <span id='city'></span>
  <span id='city2'></span>
  
          <script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>

        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.js"></script>
        <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
        <link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet">

 </body>
</html>
XYZ
  • 4,450
  • 2
  • 15
  • 31
  • adding 'vertical-align': 'middle' does solve the issue. But I am still not sure how this solution works? Note: I have marked this as the accepted answer. – vrn Jan 25 '17 at 17:44
  • 1
    Poop. So close to being first. ;-) – Nate Jan 25 '17 at 17:45
  • I dont know either.but i think it aligns the inline elements Read more here https://css-tricks.com/almanac/properties/v/vertical-align/ and http://stackoverflow.com/questions/9670469/css-vertical-alignment-of-inline-inline-block-elements – XYZ Jan 25 '17 at 17:47
0

Something's fishy with inline-flex. But I overcame the issue by adding: 'vertical-align': 'top' to elStyle:

function Dropdown() {
     this.id = '';
     this.items = [];
     
     this.settings = {
         isRendered: false,
      isListOpen: false
     };
     
     this.init = function(componentId) {
           this.id = componentId;
              this.cacheDOM();           
     };
     
     this.cacheDOM = function() {
                this.$el = $('#' + this.id);
      
                if (this.settings.isRendered)
                {
                    this.$input = this.$el.find('input');
           this.$dropbox = this.$el.find('div');
                    this.$dropdownicon = this.$el.find('span:first');
           this.$ul = this.$el.find('ul');
           this.$li = this.$ul.find('li');
                }
      
                this.template = `<div id='`+ this.id +`'>
                                              <div class='dropbox'><input /><span class='material-icons'>expand_more</span></div>
                                                       <ul style='display: none'>
                                                           {{#items}}
                                                           <li>{{.}}</li>
                                                           {{/items}}
                                              </ul>
                                         </div>`;
     };
     
     this.populateItems = function(items) {
                    this.items = items;
                    this.render();
     };
     
     this.applyStyles = function() {
      
       var elStyle = {
       'display': 'inline-block',
       'position': 'relative',
       'padding': '0',
       'margin': '0',
                            'vertical-align': 'top'
       };
       
       var dropboxStyle = {
        'display' : 'inline-flex',
        'border' : '1px solid #9DD9D2'
       };
       
       var inputStyle = {
        'font': 'inherit',
        'padding': '3px',
        'border': 'none'
       };
      
       var inputFocusStyle = {
        'border': 'none',
        'outline': 'none'
       };
      
      var dropdownIconStyle = {
         'background-color': '',
            'color': '#17BEBB'
      };
      
      var dropdownIconHoverStyle = {
        'cursor': 'default',
        'background-color': '#9DD9D2',
                             'color': 'white'
      };
      
      
      
                        this.$el.css(elStyle);
         this.$dropbox.css(dropboxStyle);
      this.$input.css(inputStyle);
      this.$input.on('focus', function() {
       $(this).css(inputFocusStyle);
      });
      this.$dropdownicon
         .css(dropdownIconStyle)
      .on('mouseenter', function() {
       $(this).css(dropdownIconHoverStyle);
      })
      .on('mouseleave', function() {
       $(this).css(dropdownIconStyle);
      });
     };
     
     this.bindEvents = function() {
      this.$dropdownicon.on('click', this.toggleList.bind(this));
      this.$li.on('mouseenter', this.toggleHoverItem.bind(this)).on('mouseleave', this.toggleHoverItem.bind(this));
      this.$li.on('click', this.itemClickHandler.bind(this));
     };
     
     this.itemClickHandler = function(event) {
      var itemSelected = $(event.target).closest('li').text();
      this.settings.isListOpen = !this.settings.isListOpen;
      this.$ul.css('display', 'none');      
      this.$input.val(itemSelected);
     }
     
     this.toggleHoverItem = function(event) {
      
      var itemMouseEnterStyle = {
       'background-color': '#9DD9D2',
       'color': 'white'
      }
      
      var itemMouseLeaveStyle = {
       'background-color': 'white',
       'color': 'black'
      }
      
      var backgroundColor = $(event.target).closest('li').css( "background-color" );
      
      if(backgroundColor == 'rgb(157, 217, 210)')
        $(event.target).closest('li').css(itemMouseLeaveStyle);
      else
                          $(event.target).closest('li').css(itemMouseEnterStyle);
     };
     
     this.toggleList = function() {
      var listOpenStyle = {
       'position': 'absolute',
       'display': 'block',
       'list-style-type': 'none',
       'border' : '1px solid #9DD9D2',
       'margin': '0',
       'padding': '2px 2px 2px 2px',
       'left': '0',
       'right': '0'
      }
      
      var listClosedStyle = {
       'display': 'none'
      }
      
      this.settings.isListOpen = !this.settings.isListOpen;
      
      if(this.settings.isListOpen)
         this.$ul.css(listOpenStyle);
      else
         this.$ul.css(listClosedStyle);
     };
     
     this.render = function() {
           var data = {items: this.items};
           this.$el.replaceWith(Mustache.render(this.template, data));
           this.settings.isRendered = true;
           this.cacheDOM();
           this.applyStyles();
           this.bindEvents();
     };
     
    };

   var dropdown = new Dropdown();
    dropdown.init('city');
    dropdown.populateItems(['Munich', 'Oslo', 'Havana']);
    dropdown.render();
   
   var dropdown2 = new Dropdown();
    dropdown2.init('city2');
    dropdown2.populateItems(['Los Angeles', 'Miami', 'Edinburg']);
    dropdown2.render();
html, body {
                height: 100%;
                width: 100%;
                overflow: hidden;
                font-size: 1em;
                font-family: 'Lato', sans-serif;
            }
<!DOCTYPE html>
<html>
 <head>
 </head>
 <body>
  
  <span id='city'></span>
  <span id='city2'></span>
  
          <script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>

        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.js"></script>
        <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
        <link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet">

 </body>
</html>
Nate
  • 1,268
  • 13
  • 20
  • Thank you for the answer. Would like to upvote this answer, but I am not allowed to. – vrn Jan 25 '17 at 17:53