I have a custom AngularJS directive for a textdown control. In it is an ng-repeat that is printing a list of div's for the emulated dropdown, and each item has an ng-click function. That function will not fire when the div is clicked. Can you please help me figure out why?
Plunkr: https://plnkr.co/edit/vOwtjqltq2WfCM9A0dFJ?p=preview
I don't remember where I first heard that concept, but it's very similar to StackOverflow's question Tags input, except you can only select 1 item. If you haven't seen that example, it is a text input that has a dropdown list when you start typing into it with related items that has fields that partially match what you've typed so far. Then the user can click on an item in the dropdown and it fills in the text input.
Here is the main page's HTML:
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>
document.write('<base href="' + document.location + '" />');
</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js@1.4.x" src="https://code.angularjs.org/1.4.7/angular.js" data-semver="1.4.7"></script>
<script src="app.js"></script>
<script src="textdown.js"></script>
</head>
<body ng-controller="MainCtrl">
<p>Hello and welcome to the Textdown example!</p>
<label>City:
<textdown input-placeholder-text="Select a City..." is-editable="true" items="cities" ng-model="selectedCity" title="Name" width="150px"></textdown>
</label>
</body>
</html>
Here is the directive's HTML:
var HYG_TEXTBOX_DROPDOWN_TEMPLATE = '\
<div class="hyg-textdown-container activate-textdown" \
ng-class="{ \'hyg-focused\': isFocused() }"> \
<input type="search" class="activate-textdown" placeholder="{{ inputPlaceholderText }}" style="width: 100%;" \
ng-class="{ \'invalid\': !isValid() }" \
ng-change="onInputChanged()" \
ng-focus="onInputFocus($event)" \
ng-model="input" \
ng-blur="onInputBlur()" \
ng-show="isEditable"> \
</input> \
<div class="hyg-textdown-list activate-textdown" ng-show="selectActive" ng-style="{ top: ytop, left: xleft }" style="z-index:5; width: {{ width }}"> \
<div class="hyg-textdown-listed activate-textdown" \
ng-repeat="item in items | property: title: (ngModel != null ? \'\' : input) | orderBy: title | limitTo:5" \
ng-class="{ \'hyg-textdown-listed-active\': isSelected(item) }" \
ng-click="selectItem(item, $event);"> \
<span class="activate-textdown">{{ item[title] }}</span> \
</div> \
</div> \
</div>';
Here is the module, directive, controller, and associated filter code:
angular.module("hyg.Textdown", [])
.directive("textdown", ["$compile", "$document", "$filter", "$log", "$timeout", function ($compile, $document, $filter, $log, $timeout) {
return {
restrict: "E",
replace: false,
controller: "hygTextdownCtrl",
template: function (element, attrs) {
return HYG_TEXTBOX_DROPDOWN_TEMPLATE;
},
require: "?ngModel",
scope: {
inputPlaceholderText: "@",
isEditable: "=",
items: "=",
ngModel: "=",
title: "@",
width: "@"
},
link: function (scope, element, attrs) {
scope.orderBy = $filter("orderBy");
if (scope.isEditable == null)
scope.isEditable = true;
$document.bind("click", function (e) {
var shouldHideSelectList = !Enumerable.From(e.target.classList).Any(function (x) { return x == "activate-textdown"; });
if (shouldHideSelectList) {
$timeout(function () { scope.selectActive = false; }, 0);
}
});
scope.destroy = function () {
if (scope.handler != null)
scope.handler();
};
scope.isFocused = function () {
return scope.focus;
};
scope.isSelectActive = function () {
return scope.selectActive;
};
scope.isValid = function () {
return scope.input == null || scope.input.length == 0 || scope.ngModel != null;
};
scope.onInputChanged = function () {
var input = scope.input == null ? null : scope.input.toLowerCase();
var item = Enumerable.From(scope.items).Where(function (x) { return x[scope.title].toLowerCase() == input; }).ToArray()[0];
scope.selectItem(item);
};
scope.onInputFocus = function ($event) {
scope.focus = true;
scope.selectActive = true;
};
scope.onInputBlur = function () {
scope.focus = false;
scope.selectActive = false;
};
scope.selectItem = function (item, $event) {
if (scope.isEditable) {
scope.ngModel = item;
if (item != null)
scope.selectActive = false;
}
};
scope.isSelected = function (item) {
return scope.ngModel == item;
};
scope.handler = scope.$watch("ngModel", function () {
if(scope.ngModel != null)
scope.input = scope.ngModel[scope.title];
});
}
}
}])
.controller("hygTextdownCtrl", ["$scope", function ($scope) {
$scope.focus = false;
$scope.handler = null;
$scope.selectActive = false;
}])
.filter("property", ["$filter", function ($filter) {
return function (array, propertyString, target) {
if (target == null)
return array;
var matched = [];
var toMatch = target.toLowerCase();
angular.forEach(array, function (item) {
if (item[propertyString].includes != undefined) {
if (item[propertyString].toLowerCase().includes(toMatch)) {
matched.push(item);
}
}
else
{
if (item[propertyString].toLowerCase().indexOf(toMatch) > -1) {
matched.push(item);
}
}
});
return matched;
}
}]);
Thanks, Jibba
答案 0 :(得分:2)
The reason why the ng-click
is not firing is because before the option is clicked, blur
event is fired on the input, which hides the options and your option never gets clicked.
You can try selecting option using ng-mousedown
instead of ng-click
.