Skip to content

Commit

Permalink
Click event handler to control resetting the component (#195)
Browse files Browse the repository at this point in the history
* Click event handler to control resetting the component

* Removed delay and async from ResetControl
also changed outside click js check for _bl_ to be more specific

Co-authored-by: Daniel Richardson <Daniel.Richardson@witherslackgroup.co.uk>
  • Loading branch information
HAL-NINE-THOUSAND and DannyRichardsonWG authored Jan 7, 2021
1 parent 11a3e33 commit 590589a
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 4 deletions.
3 changes: 1 addition & 2 deletions src/Blazored.Typeahead/BlazoredTypeahead.razor
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@
@onkeyup="HandleKeyup"
@onkeyup:stopPropagation="@StopPropagation"
@onkeyup:preventDefault="@PreventDefault"
@onblur="ResetControl"
@onfocus="HandleInputFocus"
autocomplete="off"
@attributes="AdditionalAttributes"
Expand All @@ -126,7 +125,7 @@

@if (!Disabled && EnableDropDown)
{
<div class="blazored-typeahead__input-icon" @onclick="ShowMaximumSuggestions" @onkeyup="HandleKeyUpOnShowDropDown" @onblur="ResetControl" tabindex="@(IsShowingSuggestions ? "-1" : "0")">
<div class="blazored-typeahead__input-icon" @onclick="ShowMaximumSuggestions" @onkeyup="HandleKeyUpOnShowDropDown" tabindex="@(IsShowingSuggestions ? "-1" : "0")">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24px" height="24px" viewBox="0 0 24 24" version="1.1" class="blazored-typeahead__down-arrow">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<polygon id="Shape" points="0 0 24 0 24 24 0 24" />
Expand Down
17 changes: 15 additions & 2 deletions src/Blazored.Typeahead/BlazoredTypeahead.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,17 +281,23 @@ private async Task HandleInputFocus()
}

private bool _resettingControl = false;
private async Task ResetControl()
private void ResetControl()
{
if (!_resettingControl)
{
_resettingControl = true;
await Task.Delay(200);
Initialize();
_resettingControl = false;
}
}

[JSInvokable("ResetControlBlur")]
public void ResetControlBlur()
{
ResetControl();
StateHasChanged();
}

private async Task ShowMaximumSuggestions()
{
if (_resettingControl)
Expand All @@ -315,6 +321,7 @@ private async Task ShowMaximumSuggestions()
IsSearching = false;
await InvokeAsync(StateHasChanged);
}
await HookOutsideClick();
}

private string GetSelectedSuggestionClass(TItem item, int index)
Expand Down Expand Up @@ -356,10 +363,16 @@ private async void Search(Object source, ElapsedEventArgs e)

IsSearching = false;
IsShowingSuggestions = true;
await HookOutsideClick();
SelectedIndex = 0;
await InvokeAsync(StateHasChanged);
}

private async Task HookOutsideClick()
{
await JSRuntime.OnOutsideClick(_searchInput, this, "ResetControlBlur", true);
}

private async Task SelectResult(TItem item)
{
var value = ConvertMethod(item);
Expand Down
5 changes: 5 additions & 0 deletions src/Blazored.Typeahead/Interop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,10 @@ internal static ValueTask<object> AddKeyDownEventListener(IJSRuntime jsRuntime,
{
return jsRuntime.InvokeAsync<object>("blazoredTypeahead.addKeyDownEventListener", element);
}

internal static ValueTask<object> OnOutsideClick(this IJSRuntime jsRuntime, ElementReference element, object caller, string methodName, bool clearOnFire = false)
{
return jsRuntime.InvokeAsync<object>("blazoredTypeahead.onOutsideClick", element, DotNetObjectReference.Create(caller), methodName, clearOnFire);
}
}
}
61 changes: 61 additions & 0 deletions src/Blazored.Typeahead/wwwroot/blazored-typeahead.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"use strict";

var onOutsideClickFunctions = {};

window.blazoredTypeahead = {
assemblyname: "Blazored.Typeahead",
setFocus: function (element) {
Expand All @@ -16,5 +18,64 @@ window.blazoredTypeahead = {
}
});
}
},
onOutsideClickClear: function (element) {

if (element == null) {
return;
}

var bId = "";
for (var clearCount = 0; clearCount < element.attributes.length; clearCount++) {
var a = element.attributes[clearCount];
if (a.name.startsWith('_bl_')) {
bId = a.name;
break;
}
}

var func = onOutsideClickFunctions[bId];
if (func == null || func == "undefined") {
return;
}
window.removeEventListener("click", func);
onOutsideClickFunctions[bId] = null;
},
onOutsideClick: function (searchTextElement, dotnetRef, methodName, clearOnFire) {

if (searchTextElement == null) {
return;
}

var bId = "";//get the blazor internal ID to distinguish different components
for (var clearCount = 0; clearCount < searchTextElement.attributes.length; clearCount++) {
var a = searchTextElement.attributes[clearCount];
if (a.name.startsWith('_bl_')) {
bId = a.name;
break;
}
}

blazoredTypeahead.onOutsideClickClear(searchTextElement); //clean up just in case

var func = (e) => {
var parent = e.target;
while (parent != null) {
if (parent.classList != null && parent.classList.contains('blazored-typeahead')) {
var hasSearch = parent.contains(searchTextElement); //check if this is the same typeahead parent element
if (hasSearch) {
return; //we're still in the search so don't fire
}
}
parent = parent.parentNode;
}

dotnetRef.invokeMethodAsync(methodName);
if (clearOnFire) { //could also add a check to see if the search element is missing on the DOM to force cleaning up the function?
blazoredTypeahead.onOutsideClickClear(searchTextElement);
}
};
onOutsideClickFunctions[bId] = func; //save a reference to the click function
window.addEventListener("click", func);
}
};

0 comments on commit 590589a

Please sign in to comment.