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:
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.
.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;
}
<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>
//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);
});
}
}
});
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