- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这个问题有一个 Stackblitz:stackblitz.com/edit/angular-material-starter-template-8ojscv .
我已经实现了 custom Angular Material FormField包裹 CodeMirror .
在我的 应用程序我订阅的组件 valueChanges在表单控件上听用户输入:
export class AppComponent implements OnInit {
// Custom value accessor for CodeMirror.
control: FormControl = new FormControl('', {updateOn: 'change'});
ngOnInit() {
// Listen for the user typing in CodeMirror.
this.control.valueChanges.pipe(
debounceTime(500),
distinctUntilChanged(),
tap((value: string) => {
console.log(`The user typed "${value}"`);
})
).subscribe();
}
}
我注意到在使用
setValue 时,
valueChanges Observable 发出一个值
即使选项对象禁止它 :
// This appears to have no effect.
this.control.setValue(value, {
// Prevent the statusChanges and valueChanges observables from
// emitting events when the control value is updated.
emitEvent: false,
}
my Stackblitz demo中的高层流程是:
setValue(0)
按钮 setValue
在 FormControl 上使用 emitEvent: false
writeValue(value: string)
在自定义 FormField 组件 ( my-input.component
) value
二传手value
setter 使用 this._editor.setValue(value + "")
将值写入 CodeMirror 编辑器changes
CodeMirror event被触发(它是在 ngAfterViewInit
中添加的)。 this._onChange(cm.getValue())
) valueChanges
Observable 发出更新后的值 my-input.component
显式调用注册的回调函数,但我曾期望框架(Angular 或 Angular Material)能够兑现
emitEvent: false
并且不发出事件。
emitEvent: false
,自定义FormField 实现是否有责任实现选项对象而不调用注册的回调?设置了吗?
最佳答案
我认为问题来自codemirrorValueChanged
codemirrorValueChanged(
cm: CodeMirror.Editor,
change: CodeMirror.EditorChangeLinkedList
) {
if (change.origin !== "setValue") {
console.log(`_onChange(${this.value})`);
this._onChange(cm.getValue());
}
}
但首先,让我们看看
FormControl.setValue()
上会发生什么:
setValue(value: any, options: {
onlySelf?: boolean,
emitEvent?: boolean,
emitModelToViewChange?: boolean,
emitViewToModelChange?: boolean
} = {}): void {
(this as {value: any}).value = this._pendingValue = value;
if (this._onChange.length && options.emitModelToViewChange !== false) {
this._onChange.forEach(
(changeFn) => changeFn(this.value, options.emitViewToModelChange !== false));
}
this.updateValueAndValidity(options);
}
是否使用
响应式(Reactive) 或
模板表格 ,必须设置每个控件,为此我们有
_setupControl
函数(
NgModel ,
FormControlName ),它有不同的实现,取决于指令,但在每种情况下它最终都会调用
setUpControl
:
export function setUpControl(control: FormControl, dir: NgControl): void {
if (!control) _throwError(dir, 'Cannot find control with');
if (!dir.valueAccessor) _throwError(dir, 'No value accessor for form control with');
control.validator = Validators.compose([control.validator!, dir.validator]);
control.asyncValidator = Validators.composeAsync([control.asyncValidator!, dir.asyncValidator]);
// `writeValue`: MODEL -> VIEW
dir.valueAccessor!.writeValue(control.value);
setUpViewChangePipeline(control, dir);
setUpModelChangePipeline(control, dir);
setUpBlurPipeline(control, dir);
if (dir.valueAccessor!.setDisabledState) {
/* ... */
}
/* ... */
}
setUpViewChangePipeline
是哪里
ControlValueAccessor
的
registerOnChange
将被称为:
function setUpViewChangePipeline(control: FormControl, dir: NgControl): void {
dir.valueAccessor!.registerOnChange((newValue: any) => {
control._pendingValue = newValue;
control._pendingChange = true;
control._pendingDirty = true;
// `updateControl` - update value from VIEW to MODEL
// e.g `VIEW` - an input
// e.g `MODEL` - [(ngModel)]="componentValue"
if (control.updateOn === 'change') updateControl(control, dir);
});
}
和
setUpModelChangePipeline
是哪里
_onChange
数组(来自
setValue
片段)已填充:
function setUpModelChangePipeline(control: FormControl, dir: NgControl): void {
control.registerOnChange((newValue: any, emitModelEvent: boolean) => {
// control -> view
dir.valueAccessor!.writeValue(newValue);
// control -> ngModel
if (emitModelEvent) dir.viewToModelUpdate(newValue);
});
}
所以,这就是
emitModelToViewChange
标志(来自
options.emitModelToViewChange !== false
)很重要。
updateValueAndValidity
,这是
valueChanges
的地方和
statusChanges
主题发出:
updateValueAndValidity(opts: {onlySelf?: boolean, emitEvent?: boolean} = {}): void {
this._setInitialStatus();
this._updateValue();
if (this.enabled) {
// In case of async validators
this._cancelExistingSubscription();
// Run sync validators
(this as {errors: ValidationErrors | null}).errors = this._runValidator();
(this as {status: string}).status = this._calculateStatus();
if (this.status === VALID || this.status === PENDING) {
this._runAsyncValidator(opts.emitEvent);
}
}
// !
if (opts.emitEvent !== false) {
(this.valueChanges as EventEmitter<any>).emit(this.value);
(this.statusChanges as EventEmitter<string>).emit(this.status);
}
if (this._parent && !opts.onlySelf) {
this._parent.updateValueAndValidity(opts);
}
}
因此,我们可以得出结论,问题并非源于
FormControl.setValue(val, { emitEvent: false })
.
updateValueAndValidity
被调用,我们看到
_onChange
函数将首先被调用。再一次,这样的函数看起来像这样:
// From `setUpModelChangePipeline`
control.registerOnChange((newValue: any, emitModelEvent: boolean) => {
// control -> view
dir.valueAccessor!.writeValue(newValue);
// control -> ngModel
if (emitModelEvent) dir.viewToModelUpdate(newValue);
});
在我们的例子中,
valueAccessor.writeValue
看起来像这样:
writeValue(value: string): void {
console.log(`[ControlValueAccessor] writeValue(${value})`);
// Updates the Material UI value with `set value()`.
this.value = value;
}
这将调用setter:
set value(value: string | null) {
console.log(`[MatFormFieldControl] set value(${value})`);
if (this._editor) {
this._editor.setValue(value + "");
this._editor.markClean();
// Postpone the refresh() to after CodeMirror/Browser has updated
// the layout according to the new content.
setTimeout(() => {
this._editor.refresh();
}, 1);
}
this.stateChanges.next();
}
由于
_editor.setValue
,
onChanges
事件将发生和
codemirrorValueChanged
将被调用:
codemirrorValueChanged(
cm: CodeMirror.Editor,
change: CodeMirror.EditorChangeLinkedList
) {
if (change.origin !== "setValue") {
console.log(`_onChange(${this.value})`);
this._onChange(cm.getValue());
}
}
什么
_onChange
是否调用此回调:
// from `setUpViewChangePipeline`
dir.valueAccessor!.registerOnChange((newValue: any) => {
control._pendingValue = newValue;
control._pendingChange = true;
control._pendingDirty = true;
if (control.updateOn === 'change') updateControl(control, dir);
});
和
updateControl
将调用
control.setValue
,但是
没有
emitEvent: false
:
function updateControl(control: FormControl, dir: NgControl): void {
if (control._pendingDirty) control.markAsDirty();
control.setValue(control._pendingValue, {emitModelToViewChange: false});
dir.viewToModelUpdate(control._pendingValue);
control._pendingChange = false;
}
因此,这应该可以解释当前的行为。
change
是一个数组,而不是一个对象。
codemirrorValueChanged(
cm: CodeMirror.Editor,
change: CodeMirror.EditorChangeLinkedList
) {
if (change[0].origin !== "setValue") {
console.log(`_onChange(${this.value})`);
this._onChange(cm.getValue());
}
}
关于angular - 自定义 Angular FormField 在配置为不触发时发出事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62762453/
好的,所以我编辑了以下... 只需将以下内容放入我的 custom.css #rt-utility .rt-block {CODE HERE} 但是当我尝试改变... 与 #rt-sideslid
在表格 View 中,我有一个自定义单元格(在界面生成器中高度为 500)。在该单元格中,我有一个 Collection View ,我按 (10,10,10,10) 固定到边缘。但是在 tablev
对于我的无能,我很抱歉,但总的来说,我对 Cocoa、Swift 和面向对象编程还很陌生。我的主要来源是《Cocoa Programming for OS X》(第 5 版),以及 Apple 的充满
我正在使用 meta-tegra 为我的 NVIDIA Jetson Nano 构建自定义图像。我需要 PyTorch,但没有它的配方。我在设备上构建了 PyTorch,并将其打包到设备上的轮子中。现
在 jquery 中使用 $.POST 和 $.GET 时,有没有办法将自定义变量添加到 URL 并发送它们?我尝试了以下方法: $.ajax({type:"POST", url:"file.php?
Traefik 已经默认实现了很多中间件,可以满足大部分我们日常的需求,但是在实际工作中,用户仍然还是有自定义中间件的需求,为解决这个问题,官方推出了一个 Traefik Pilot[1] 的功
我想让我的 CustomTextInputLayout 将 Widget.MaterialComponents.TextInputLayout.OutlinedBox 作为默认样式,无需在 XML 中
我在 ~/.emacs 中有以下自定义函数: (defun xi-rgrep (term) (grep-compute-defaults) (interactive "sSearch Te
我有下表: 考虑到每个月的权重,我的目标是在 5 个月内分散 10,000 个单位。与 10,000 相邻的行是我最好的尝试(我在这上面花了几个小时)。黄色是我所追求的。 我试图用来计算的逻辑如下:计
我的表单中有一个字段,它是文件类型。当用户点击保存图标时,我想自然地将文件上传到服务器并将文件名保存在数据库中。我尝试通过回显文件名来测试它,但它似乎不起作用。另外,如何将文件名添加到数据库中?是在模
我有一个 python 脚本来发送电子邮件,它工作得很好,但问题是当我检查我的电子邮件收件箱时。 我希望该用户名是自定义用户名,而不是整个电子邮件地址。 最佳答案 发件人地址应该使用的格式是: You
我想减小 ggcorrplot 中标记的大小,并减少文本和绘图之间的空间。 library(ggcorrplot) data(mtcars) corr <- round(cor(mtcars), 1)
GTK+ noob 问题在这里: 是否可以自定义 GtkFileChooserButton 或 GtkFileChooserDialog 以删除“位置”部分(左侧)和顶部的“位置”输入框? 我实际上要
我正在尝试在主页上使用 ajax 在 magento 中使用 ajax 显示流行的产品列表,我可以为 5 或“N”个产品执行此操作,但我想要的是将分页工具栏与结果集一起添加. 这是我添加的以显示流行产
我正在尝试使用 PasswordResetForm 内置函数。 由于我想要自定义表单字段,因此我编写了自己的表单: class FpasswordForm(PasswordResetForm):
据我了解,新的 Angular 7 提供了拖放功能。我搜索了有关 DnD 的 Tree 组件,但没有找到与树相关的内容。 我在 Stackblitz 上找到的一个工作示例.对比drag'ndrop功能
我必须开发一个自定义选项卡控件并决定使用 WPF/XAML 创建它,因为我无论如何都打算学习它。完成后应该是这样的: 到目前为止,我取得了很好的进展,但还有两个问题: 只有第一个/最后一个标签项应该有
我要定制xtable用于导出到 LaTeX。我知道有些问题是关于 xtable在这里,但我找不到我要找的具体东西。 以下是我的表的外观示例: my.table <- data.frame(Specif
用ejs在这里显示日期 它给我结果 Tue Feb 02 2016 16:02:24 GMT+0530 (IST) 但是我需要表现为 19th January, 2016 如何在ejs中执行此操作?
我想问在 JavaFX 中使用自定义对象制作 ListView 的最佳方法,我想要一个每个项目如下所示的列表: 我搜了一下,发现大部分人都是用细胞工厂的方法来做的。有没有其他办法?例如使用客户 fxm
我是一名优秀的程序员,十分优秀!