Angular editable dropdown - make editable based on selected value

前端 未结 2 950
轮回少年
轮回少年 2021-01-06 22:43

UPDATE 1: developed the first sample code to set the basis for correct implementation.
UPDATE 2: developed a working model. See answers.

I found this library:

相关标签:
2条回答
  • 2021-01-06 23:16

    Here is my solution. This is based on another post, but I cannot remember the source. Thanks to all who helped.

    Just add the attribute editable-dropdown against the select element. The value of the attribute must be the ID of the input element.

    Style:

    .stop-wrap {
        display: inline-block;
    }
    
    .select-editable {
        position:relative;
        background-color:white;
        border:solid grey 1px;
        width:120px;
        height:25px;
        vertical-align: middle;
        margin-bottom: 5px;
    }
    .select-editable select {
        position:absolute;
        top:0px;
        left:0px;
        border:none;
        width:118px;
        margin:0;
    }
    .select-editable input {
        position:absolute;
        top:0px;
        left:0px;
        width:100px;
        padding:1px;
        border:none;
    }
    .select-editable select:focus, .select-editable input:focus {
        outline:none;
    }
    

    HTML:

    <div class="select-editable stop-wrap">
        <select editable-dropdown="input_elem" id="input_elem_sel" name="input_elem_sel">
              <option value=""></option>
              <option value="Option 1">Option 1</option>
              <option value="Option 2">Option 2</option>
              <option value="Option 3">Option 3</option>
              <option value="Option 4">Option 4</option>
              <option value="Other">Other ...</option>
        </select>
        <input id="input_elem" name="input_elem" ng-model="input_elem" force-model-update>
    </div>
    

    JavaScript:

    //This uses two fields, SELECT and INPUT. The input element is identfied by the attribute 'editableDropdown'
    app.directive('editableDropdown', function (){
        return {
            link: function (scope, elemSel, attrs) {
                //debugger;
                var inpElemID = attrs.editableDropdown;
                var inpElem;
                //The parameter 'elemSel' is the SELECT field
                function initInpElem() {
                    if ($(elemSel).is("select")) {
                        inpElem = $('#' + inpElemID);
                    } else {
                        //This is in case the Dropdown is based on DATALIST which is not yet implemented
                        //In this case, the input element is actually the same as the dropdown field using DATALIST
                        inpElem = elemSel;
                    }
                }
                function updateEditable(elm) {
                    initInpElem();
                    //Copy value from SELECT element to the INPUT Element
                    //Use NgModelController to copy value in order to trigger validation for 'inpElem'
                    var selectedValue = $(elm).children("option").filter(":selected").text();
                    //or var selectedValue = elm.val();
                    //TODO: will have to add more control here since the SELECT value and text are not the same
                    //      Might cause some issue while rendering value in PDF.
                    angular.element(inpElem).controller('ngModel').$setViewValue(elm.val());
                    angular.element(inpElem).controller('ngModel').$render();
                    makeEditable(elm);
                }
                function makeEditable(selElm) {
                    //debugger;
                    initInpElem();
                    if ($(selElm).is("select")) {
                        if (selElm.val() == "Other") {
                              $(inpElem).prop("readonly", false);
                        } else {
                              $(inpElem).prop("readonly", true);
                        }
                    } else {
                        //This part is not yet implemented. It is to be completed and verified in case the dropdown is `datalist`. You can skip this part.
                        if (elm.value != "Other" && !$(elm).attr("keypressOff")) {
                            $(elm).keypress(function(event) {
                                console.log("keypress preventd")
                                event.preventDefault();
                            })
                        } else {
                            $(elm).off("keypress");
                            $(elm).attr("keypressOff", true);
                            console.log("keypress event removed")
                        }
                    }
                }           
                angular.element(document).ready(function(){
                    makeEditable(elemSel);
                });
                $(elemSel).change(function () {
                    updateEditable(elemSel);
                });
            }
        }
    });
    
    0 讨论(0)
  • 2021-01-06 23:17

    Seems like you are not attracting too much attention to your question and as I commented, you'd (still) be better off writing your own implementation rather than trying to force editable-dropdown-angular to your needs.

    Anyway, I took liberty of writing my own editable-select directive for you.

    Directive takes array of options to choose from and optional other string, which is default value for user-editable selection. Editing is disabled while choosing from options, while other can be freely modified.

    Hope you find it useful.

    App HTML template

    <body ng-controller="Ctrl as vm">
      <!-- directive -->
      <editable-select 
        ng-model="vm.selected" 
        options="vm.options" 
        other="Other"> <!-- write "other" here or assign var in controller -->
      </editable-select>
    
      <hr>
      <span>User selected: {{ vm.selected }}</span>
    </body>
    

    App JavaScript

    angular
    .module('app', [])    
    .controller('Ctrl', function() {
      var vm = this;
      vm.options = ['One', 'Two']; // selection options
    })    
    .directive('editableSelect', function() {
      return {
        restrict: 'E',
        require: '^ngModel',
        scope: {
          ngModel: '=',
          options: '=',
          other: '@'
        },
        replace: true,
        templateUrl: 'editable-select-tpl.html', 
        link: function(scope, element) {
          scope.isDisabled = true;
    
          // option clicked handler    
          scope.click = function(option) {
            scope.ngModel = option;
            scope.isDisabled = !scope.other || scope.other !== option;
            if (!scope.isDisabled) {
              element[0].querySelector('.editable-select').focus();
            }
          };
    
          // option typed handler          
          var unwatch = scope.$watch('ngModel', function(val) {
            if (!scope.isDisabled) {
              scope.other = scope.ngModel;
            }
          });
    
          // release watcher          
          scope.$on('$destroy', unwatch);
        }
      };
    }); 
    

    Directive HTML template (editable-select-tpl.html)

    <div>
      <div class="input-group dropdown">
        <input name="editable-select" 
               type="text" 
               class="form-control dropdown-toggle editable-select" 
               ng-disabled="isDisabled" 
               ng-model="ngModel">
        <ul class="dropdown-menu">
          <li ng-repeat="option in options" 
              ng-bind="::option" 
              ng-click="click(option)">
          </li>
          <li ng-if="other" role="presentation" class="divider"></li>
          <li ng-if="other" ng-bind="other" ng-click="click(other)"></li>
        </ul>
        <span class="input-group-addon dropdown-toggle" data-toggle="dropdown">
          <span class="caret"></span>
        </span>
      </div>
      <span class="small text-muted" ng-show="!isDisabled">Type in your selection</span>
    </div>
    

    CSS

    input[name="editable-select"]:disabled {
      background-color: #ffffff;
    }
    
    .dropdown-menu:hover {
      cursor: pointer;
    }
    
    .dropdown-menu li {
      padding-left: 10px;
    }
    
    .dropdown-menu li:hover {
      background-color: #eeeeee;
    }
    

    Related plunker here https://plnkr.co/edit/7bVgDW

    0 讨论(0)
提交回复
热议问题