chciałbym zaproponować, aby przenieść rozmowę debounceTime
tuż po strumieniem tekstowym i zrobić filtrowanie już na debounced strumienia. W ten sposób ważna, ale nieaktualna wartość nie będzie przekradać się do wywołania ajax. Ponadto, być może będziemy musieli "anulować" wywołanie ajaxowe (lub dokładniej, zignorować jego odpowiedź), gdy pojawi się nowe, prawdopodobnie nieprawidłowe, dane wejściowe, ponieważ nie chcemy, aby status "nieprawidłowy" został zmieniony z wynikiem trwającego asynchronicznego połączenie. takeUntil
może w tym pomóc. Zauważ też, że zamiast $.ajax()
można użyć Rx.Observable.ajax()
.
BTW, może być przydatny, aby mieć dedykowany strumień "statusów sprawdzania poprawności", aby this.username_validation_display(validationStatus)
było wykonane w jednym miejscu wewnątrz subskrypcji.
sobie wyobrazić, że jest coś takiego:
const term$ = Rx.Observable.fromEvent(textInput, "keyup")
.pluck("target", "value")
.map(text => text.trim())
.distinctUntilChanged()
.share();
const suggestion$ = term$
.debounceTime(300)
.filter(term => getValidationError(term).length === 0)
.switchMap(term => Rx.Observable
.ajax({
method: "POST",
url: "src/php/search.php",
body: {
username: term,
type: "username"
}
})
.takeUntil(term$)
)
.map(result => JSON.parse(result));
const validationStatus$ = Rx.Observable.merge(
term$.map(getValidationError),
suggestion$.map(getSuggestionStatus));
// "empty", "invalid", "taken", "valid" or ""
validationStatus$
.subscribe(validationStatus => this.username_validation_display(validationStatus));
// Helper functions
function getValidationError(term) {
if (term.length === 0) {
return "empty";
}
if (!/^\w{1,20}$/.test(term)) {
return "invalid";
}
return "";
}
function getSuggestionStatus(suggestion) {
return suggestion.length > 0 ? "taken" : "valid";
}
Zachowanie kodu powyżej byłaby również inna w tym sensie, że między punktem w czasie, gdy użytkownik wpisał poprawny wejście i punkt po otrzymaniu sugestii z serwera, username_validation_display
będzie miało pustą wartość, tj. oprócz statusów "pusty", "nieprawidłowy", "zajęty" i "prawidłowy" będzie również pusty status pośredni, który może zostać zastąpiony pewnym wskaźnikiem postępu w interfejsie użytkownika.
Aktualizacja: mogę również pomyśleć o alternatywnym podejściu, które powinien posiadać równoważne zachowanie, ale odpowiadający kod może wyglądać nieco bardziej prosta:
const username$ = Rx.Observable.fromEvent(textInput, "keyup")
.pluck("target", "value")
.map(text => text.trim())
.distinctUntilChanged();
const validationStatus$ = username$.switchMap(username => {
const validationError = getValidationError(username);
return validationError ?
Rx.Observable.of(validationError) :
Rx.Observable.timer(300)
.switchMapTo(getAvailabilityStatus$(username))
.startWith("pending");
});
// "invalid", "empty", "taken", "valid" or "pending"
validationStatus$.subscribe(
validationStatus => this.username_validation_display(validationStatus));
// Helper functions
function getAvailabilityStatus$(username) {
return Rx.Observable
.ajax({
method: "POST",
url: "src/php/search.php",
body: {
username: username,
type: "username"
}
})
.map(result => JSON.parse(result))
.map(suggestions => suggestions.length > 0 ? "taken" : "valid");
}
function getValidationError(username) {
if (username.length === 0) {
return "empty";
}
if (!/^\w{1,20}$/.test(username)) {
return "invalid";
}
return null;
}
ten sposób możemy sprawdzić każdego odrębnego wejścia synchronicznie. Jeśli dane wejściowe są puste lub nieprawidłowe (określone przez wywołanie getValidationError()
), natychmiast wysyłamy komunikat o błędzie weryfikacji. W przeciwnym razie natychmiast wyślemy status "oczekujący" i uruchomimy timer, który po 300 ms uruchomi sprawdzanie dostępności asynchronicznej nazwy użytkownika. Jeśli nadejdzie nowy tekst przed upływem czasu lub stan dostępności nadejdzie z serwera, anulujemy wewnętrzny strumień i ponownie uruchomimy sprawdzanie poprawności, dzięki switchMap
. Powinno działać tak samo jak z debounceTime
.
Jak widzę już filtrowanie wartości obserwowalnych przez 'text.length> 0', więc nie powinno nic zastąpić. Aby lepiej zrozumieć swój problem, możesz podać działający fragment kodu? –
@OlesSavluk Problem polega na tym, że jeśli wpiszesz pojedynczą literę, a następnie cofnę ją, to nadal będzie wysyłać żądanie przez literę i odzyskać odpowiedź. Na przykład. Wpisuję 'e', a następnie cofam. Nadal będę uzyskiwał wyniki z 'e'. Ale tak, będę musiał wymyślić sposób na stworzenie fragmentu. –