mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
DEV: Support for onChange
on {{text-field}}
(#9362)
* DEV: Support for `onChange` on `{{text-field}}` This will automatically be debounced and only fired when the value changes. There is also `onChangeImmediate` which is not debounced in case you need that, but in almost all cases when observing text in an element you should debounce. * Add cancel for timer
This commit is contained in:
parent
09145e68cd
commit
4f42bb1fd2
@ -1,8 +1,14 @@
|
||||
import { TextField } from "@ember/component";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { siteDir, isRTL, isLTR } from "discourse/lib/text-direction";
|
||||
import { next, debounce, cancel } from "@ember/runloop";
|
||||
|
||||
const DEBOUNCE_MS = 500;
|
||||
|
||||
export default TextField.extend({
|
||||
_prevValue: null,
|
||||
_timer: null,
|
||||
|
||||
attributeBindings: [
|
||||
"autocorrect",
|
||||
"autocapitalize",
|
||||
@ -11,6 +17,28 @@ export default TextField.extend({
|
||||
"dir"
|
||||
],
|
||||
|
||||
didReceiveAttrs() {
|
||||
this._super(...arguments);
|
||||
this._prevValue = this.value;
|
||||
},
|
||||
|
||||
didUpdateAttrs() {
|
||||
this._super(...arguments);
|
||||
if (this._prevValue !== this.value) {
|
||||
if (this.onChangeImmediate) {
|
||||
next(() => this.onChangeImmediate(this.value));
|
||||
}
|
||||
if (this.onChange) {
|
||||
cancel(this._timer);
|
||||
this._timer = debounce(this, this._debouncedChange, DEBOUNCE_MS);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_debouncedChange() {
|
||||
next(() => this.onChange(this.value));
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
dir() {
|
||||
if (this.siteSettings.support_mixed_text_direction) {
|
||||
@ -23,6 +51,11 @@ export default TextField.extend({
|
||||
}
|
||||
},
|
||||
|
||||
willDestroyElement() {
|
||||
this._super(...arguments);
|
||||
cancel(this._timer);
|
||||
},
|
||||
|
||||
keyUp(event) {
|
||||
this._super(event);
|
||||
|
||||
|
@ -44,3 +44,43 @@ componentTest("sets the dir attribute to ltr for English text", {
|
||||
assert.equal(find("input").attr("dir"), "ltr");
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("supports onChange", {
|
||||
template: `{{text-field class="tf-test" value=value onChange=changed}}`,
|
||||
beforeEach() {
|
||||
this.called = false;
|
||||
this.newValue = null;
|
||||
this.set("value", "hello");
|
||||
this.set("changed", v => {
|
||||
this.newValue = v;
|
||||
this.called = true;
|
||||
});
|
||||
},
|
||||
async test(assert) {
|
||||
await fillIn(".tf-test", "hello");
|
||||
assert.ok(!this.called);
|
||||
await fillIn(".tf-test", "new text");
|
||||
assert.ok(this.called);
|
||||
assert.equal(this.newValue, "new text");
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("supports onChangeImmediate", {
|
||||
template: `{{text-field class="tf-test" value=value onChangeImmediate=changed}}`,
|
||||
beforeEach() {
|
||||
this.called = false;
|
||||
this.newValue = null;
|
||||
this.set("value", "old");
|
||||
this.set("changed", v => {
|
||||
this.newValue = v;
|
||||
this.called = true;
|
||||
});
|
||||
},
|
||||
async test(assert) {
|
||||
await fillIn(".tf-test", "old");
|
||||
assert.ok(!this.called);
|
||||
await fillIn(".tf-test", "no longer old");
|
||||
assert.ok(this.called);
|
||||
assert.equal(this.newValue, "no longer old");
|
||||
}
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user