MEAN栈中AngularJS自定义下拉指令无法绑定滚动函数
Hey there, let's tackle that scroll binding issue with your custom dropdown directive! From the code snippet you shared, it looks like you're building an autocomplete-style dropdown, and you want to attach a scroll handler (probably for things like infinite scrolling or loading more options as the user scrolls). Here's how to get it working smoothly:
First, Let's Cover the Basics
Before diving into code, make sure your dropdown container has fixed height and scrollable overflow—without this, the scroll event won't trigger at all. Add these styles to your .dropdown1 class:
.dropdown1 { max-height: 250px; /* Adjust based on your UI needs */ overflow-y: auto; /* Add any other styling you need (border, position, etc.) */ }
Updated Directive with Scroll Binding
Here's a revised version of your directive that properly binds the scroll event, with explanations of key changes:
.directive('inputDropdown', function($parse, $timeout) { // Use template literals for cleaner multi-line templates var template = ` <input class="form-control" ng-model="ngModel" ng-disabled="disabled" placeholder="Type Name"> <div class="dropdown dropdown1"> <div class="form-control" ng-repeat="value in selectedList | filter:ngModel | limitTo:limit"> <div ng-mousedown="select($event, value)">{{value.name}}</div> </div> </div> `; return { restrict: 'E', template: template, // Isolate scope for better data binding control scope: { ngModel: '=', disabled: '=', selectedList: '=', limit: '=', onScroll: '&' // Expose a callback for parent components to handle scroll logic }, link: function(scope, element, attrs) { // Wait for the DOM to fully render (critical if dropdown is initially hidden) $timeout(() => { // Grab the dropdown container element const dropdownContainer = element[0].querySelector('.dropdown1'); if (!dropdownContainer) return; // Define your scroll handler const handleScroll = function() { // Example: Check if user scrolled to the bottom const isScrolledToBottom = (this.scrollTop + this.clientHeight) >= this.scrollHeight - 10; // 10px buffer if (isScrolledToBottom) { // Use $apply to trigger Angular's digest cycle (updates view) scope.$apply(() => { // Call the parent's scroll callback (e.g., load more items) scope.onScroll(); }); } }; // Attach the scroll event listener dropdownContainer.addEventListener('scroll', handleScroll); // Clean up the event listener when the directive is destroyed (prevents memory leaks) scope.$on('$destroy', () => { dropdownContainer.removeEventListener('scroll', handleScroll); }); }); // Your existing select function (completed for context) scope.select = function(event, value) { scope.ngModel = value; // Add any other logic (like closing the dropdown) here }; } }; })
Key Changes Explained
- Isolate Scope: Using
scope: {}ensures your directive doesn't leak or clash with parent scope variables, and makes it easier to pass in callbacks likeonScroll. - DOM Render Wait: The
$timeoutensures we only bind the scroll event after the dropdown container is fully rendered—this is crucial if your dropdown is hidden initially (e.g., withng-showorng-hide). - Native Event Binding: Using vanilla JS
addEventListeneris more reliable than Angular's built-in directives for scroll events on custom elements, and gives you full control over the event logic. - Cleanup: Removing the event listener on
$destroyprevents memory leaks when the directive is removed from the DOM.
Using the Directive in Your Template
To use the scroll callback, pass in a function from your parent controller:
<input-dropdown ng-model="selectedItem" disabled="isDisabled" selected-list="itemList" limit="10" on-scroll="loadMoreItems()"> </input-dropdown>
And in your controller, define the loadMoreItems function to handle loading additional data:
$scope.loadMoreItems = function() { // Example: Increase the limit to load more items $scope.limit += 10; // Or make an API call to fetch more data and add to selectedList };
内容的提问来源于stack exchange,提问作者techie

