Popup

by namlth

HTML

<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://github.com/SteveSanderson/knockout-projections/blob/master/dist/knockout-projections.js"></script>
<link rel="stylesheet" href="https://rawgit.com/daneden/animate.css/master/animate.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.2.1/lodash.min.js"></script>
<div class="container main-container">
  <div class="row mt-3">
    <div class="col-12">
      <div class="form-group">
        <div class="input-group address-book-group">
          <input type="text" class="form-control" data-bind="value: activeItem().name"/>
          <a href="#" class="btn btn-address-book" data-bind="click: addressBookClick">
            <i class="fa fa-address-book"></i>
          </a>
          <div class="address-book-popup animated" 
               data-bind="css: { 
                          'active fadeIn': isActive,
                          'no-arrow': hasNoArrow,
                          'top-zero': hasTopZero,
                          'no-padding': hasNoPadding
                          }">
            <div class="panel-top">
              <div class="input-group">
                <div class="input-group-prepend">
                  <span class="input-group-text input-group-text--mod"><i class="fa fa-search"></i></span>
                </div>
                <input type="text" class="form-control form-control--mod" placeholder="Search" data-bind="value: filter, valueUpdate: 'afterkeyup'"/>
                <div class="input-group-append">
                  <span class="input-group-text...

SCSS

.main-container {
  //min-height: 500px;
  //overflow-y: auto;
}

.btn-address-book:focus {
  //border: 1px solid blue;
  outline: none;
  box-shadow: none;
}

.btn-close {
  color: lightgray;
}

.address-book-group {
  position: relative;
}

.address-book-popup {
  animation-duration: 2s;
  display: none;
  position: absolute;
  z-index: 9999;
  background: white;
  left: 0;
  top: 100%;
  border: 1px solid black;
  border-radius: 0.25rem;
  -webkit-box-shadow: 2px 2px 5px 0px rgba(0,0,0,0.75);
  -moz-box-shadow: 2px 2px 5px 0px rgba(0,0,0,0.75);
  box-shadow: 2px 2px 5px 0px rgba(0,0,0,0.75);
  width: 100%;
  //min-height: 50vmin;
  //max-height: 70vmin;
  margin-top: 0.25rem;
  //background: lightblue;
  flex-direction: column;
  justify-content: space-between;
  padding: 0.5rem;
  .input-group-prepend {
    .input-group-text--mod {
      background: none;
      border: none;
      position: absolute;
      top: 50%;
      z-index: 9999;
      transform: translateY(-50%);
    }
  }
  .form-control--mod {
    padding-left: 40px;
    border-radius: 0.25rem !important;
  }
  .input-group-append {
    .input-group-text--mod {
      background: none;
      border: none;
    }
  }
  .btn-main {
    border: none;
    border-radius: 0;
    background: none;
    width: 100%;
    border-right: 1px solid blue;
    color: green;
  }
  .btn-main:focus {
    outline: none;
    box-shadow: none;
  }
  .panel-top {}
  .panel-bottom {
    display: flex;
    margin-bottom: -0.5rem;
    margin-left: -0.5rem;
    margin-right: -0.5rem;
    border-top: 1px solid blue;
    border-top-left-radius: 0.25rem;
    border-top-right-radius: 0.25rem;
  }
  .panel-main {
    //background: lightgreen;
    //height: 100%;
    //min-height: 30vh;
    max-height: 60vh;
    overflow-y: scroll;
    -webkit-overflow-scrolling: touch;
    position: relative;
    margin-top: 0.5rem;
    margin-bottom: 0.5rem;
    .list-group-item.active {
      background: lightgray;
    }
 ...

TypeScript

function myModel() {
  var that = this;
  /*
  ** Setup UI
  */
  that.hasNoArrow = ko.observable(false);
  that.hasTopZero = ko.observable(false);
  that.hasNoPadding = ko.observable(false);
  /* end */
  
  that.items = ko.observableArray([
    { id: 1, name: 'Nam Le 1' },
    { id: 2, name: 'Nam Le 2' },
    { id: 3, name: 'Nam Le 3' },
    { id: 4, name: 'Nam Le 4' },
    { id: 5, name: 'Nam Le 5' },
    { id: 6, name: 'Nam Le 6' },
    { id: 7, name: 'Nam Le 7' },
    { id: 8, name: 'Nam Le 8' },
    { id: 9, name: 'Nam Le 9' },
    { id: 10, name: 'Abc 10' },
    { id: 11, name: 'Zye 11' },
    { id: 12, name: 'Eye 12' },
    { id: 13, name: 'Mouse 13' },
  ]);

  that.filter = ko.observable("");

  that.filteredItems = ko.dependentObservable(function() {
    var filter = that.filter().toLowerCase();
    if (!filter) {
      return that.items();
    } else {
      return ko.utils.arrayFilter(that.items(), function(item) {
        return item.name.toLowerCase().indexOf(filter) !== -1;
      });
    }
  });

  that.isActive = ko.observable(false);
  that.activeItemId = ko.observable(0);

  that.activeItem = ko.computed(() => {
    if (that.activeItemId() === 0) return "";

    var item = that.items().filter((x) => { return x.id === that.activeItemId() })[0];

    var itemArray = ko.utils.arrayFilter(that.items(), (itemA) => {
      return itemA.id === that.activeItemId();
    });

    alert(itemArray);

    return item;
  });

  that.isItemActive = (itemId) => {
    return itemId === that.activeItemId();
  };

  that.addressBookClick = () => {
    that.isActive(!that.isActive());
  };

  that.addressItemClick = (itemId) => {
    that.activeItemId(itemId);
  };
};


ko.applyBindings(new myModel());