- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我在使用 Angular 6 时遇到以下错误
<mat-tab-group [(selectedIndex)]="selectedTabIndex">
<mat-tab label="Add">
<ng-template matTabContent>
<form [formGroup]="entityAddFormGroup">
<dynamic-material-form [group]="entityAddFormGroup" [model]="entityAddFormCtlModelArray"></dynamic-material-form>
<button (click)="buttonAddEntityClicked(entityAddFormGroup.value)">Add</button>
</form>
</ng-template>
</mat-tab>
<mat-tab *ngIf="entityEditFormGroup && currentEntity" label="Edit #{{currentEntity.id}}">
<!-- TODO correct bug with -->
<ng-template matTabContent>
<form [formGroup]="entityEditFormGroup">
<!-- <h2 i18n>Edit #{{currentEntity.id}}</h2> -->
<dynamic-material-form [group]="entityEditFormGroup" [model]="entityEditFormCtlModelArray"></dynamic-material-form>
<button (click)="buttonEditEntityClicked(entityEditFormGroup.value)">Save</button>
</form>
</ng-template>
</mat-tab>
</mat-tab-group>
当我删除第二个 mat-tab
时,错误消失了
在其他类似的组件中,我没有把这2个表单放到mat-tab-group
和mat-tab
中,也没有出现这个错误。
花了一些时间来发现不同之处。
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'ng-valid: true'. Current value: 'ng-valid: false'.
Angular CLI: 6.2.8
Node: 11.9.0
OS: linux x64
Angular:
public displayedColumnsArray = [
'select',
'id',
'energyRate',
'mainTransmissionRate',
'publicServiceRate',
'validityStartDate',
'validityEndDate',
'electricityType',
'city',
]; // Gives the order of the columns
public statusMessage: string = ''
public selectedTabIndex: number = 0
protected _elTypeAddSelect: DBEntitySelect<Enumerate> //ElectricityType: Enumerate
protected _elTypeEditSelect: DBEntitySelect<Enumerate> //ElectricityType: Enumerate
protected _cityAddSelect: DBEntitySelect<Enumerate> //City: Enumerate
protected _cityEditSelect: DBEntitySelect<Enumerate> //City: Enumerate
constructor(
protected router: Router,
public messageService: MessageService,
protected logger: LoggerService,
protected route: ActivatedRoute,
protected entitiesService: ElectricityRateService,
protected enumeratesService: EnumerateService,
protected formBuilder: FormBuilder,
public formService: DynamicFormService,
iconRegistry: MatIconRegistry,
sanitizer: DomSanitizer,
// private location: Location
) {
super(router, messageService, logger, route, entitiesService, formBuilder, formService, iconRegistry, sanitizer, new ElectricityRate());
(...)
}
/**
* Common to add and edit forms
*
* @param aStrangeObject
*/
protected _getCommonFormControlModel(aStrangeObject: Enumerate): DynamicFormControlModel[] {
let lEntity: ElectricityRate = new ElectricityRate().deserialize(
aStrangeObject
)
console.debug(
"-----getAddFormControlModel->",
aStrangeObject,
lEntity.validityStartDate.constructor.name,
lEntity.validityEndDate.constructor.name
)
const result: DynamicFormControlModel[] = [
new DynamicInputModel({
id: "energyRate",
label: "Energy Rate",
value: lEntity.energyRate,
inputType: DYNAMIC_FORM_CONTROL_INPUT_TYPE_NUMBER,
min: ElectricityRate.MIN_ELECTRICITY_RATE,
max: ElectricityRate.MAX_ELECTRICITY_RATE,
placeholder: "Energy Rate"
}),
new DynamicInputModel({
id: "mainTransmissionRate",
label: "Transmission Rate",
inputType: DYNAMIC_FORM_CONTROL_INPUT_TYPE_NUMBER,
min: ElectricityRate.MIN_ELECTRICITY_RATE,
max: ElectricityRate.MAX_ELECTRICITY_RATE,
value: lEntity.mainTransmissionRate.toString(),
placeholder: "Transmission Rate"
}),
new DynamicInputModel({
id: "publicServiceRate",
label: "Public Service Rate",
inputType: DYNAMIC_FORM_CONTROL_INPUT_TYPE_NUMBER,
min: ElectricityRate.MIN_ELECTRICITY_RATE,
max: ElectricityRate.MAX_ELECTRICITY_RATE,
value: lEntity.publicServiceRate.toString(),
placeholder: "Public Service Rate"
}),
new DynamicInputModel({
id: "validityStartDate",
label: "Validity start date",
inputType: DYNAMIC_FORM_CONTROL_INPUT_TYPE_DATE,
maxLength: 10,
value: MiscHelper.dateToDynamicInputDate(lEntity.validityStartDate),
placeholder: "Validity start date"
}),
new DynamicInputModel({
id: "validityEndDate",
label: "Validity end date",
inputType: DYNAMIC_FORM_CONTROL_INPUT_TYPE_DATE,
value: MiscHelper.dateToDynamicInputDate(lEntity.validityEndDate),
placeholder: "Validity end date"
})
]
return result
}
/**
* called by SelectableEntitiesListComponent->onInit
*
* @param aStrangeObject
*/
protected _getAddFormControlModel(aStrangeObject: Enumerate): DynamicFormControlModel[] {
//console.debug('getAddFormControlModel->aStrangeObject:', aStrangeObject)
let lEntity: Enumerate = new Enumerate().deserialize(aStrangeObject)
console.debug('-----getAddFormControlModel->aStrangeObject, lEntity:', aStrangeObject, lEntity)
//Add form fields
const result: DynamicFormControlModel[] = this._getCommonFormControlModel(aStrangeObject)
result.push(this._elTypeAddSelect.asDynamicInputModel())
result.push(this._cityAddSelect.asDynamicInputModel())
return result
}
/**
* Built onRowClicked
*
* @param anId
* @param aStrangeObject can be a row of dataTable
*/
protected _getEditFormControlModel(aStrangeObject: Enumerate): DynamicFormControlModel[] {
console.log('getEditFormControlModel:', aStrangeObject)
let result = this._getCommonFormControlModel(aStrangeObject)
result = result.concat(DBEntity.getIdFormControlModel('id', aStrangeObject))
result.push(this._elTypeEditSelect.asDynamicInputModel())
result.push(this._cityEditSelect.asDynamicInputModel())
// console.log('getEditFormControlModel:', result)
return result
}
public ngOnInit() {
super.ngOnInit()
this._setSelects()
}
/**
* redefine
*/
public onReloadClicked(anEvent) {
super.onReloadClicked(anEvent)
this._setSelects()
}
/**
* redefine
*/
public afterEntityUpdatedSucessful(){
super.afterEntityUpdatedSucessful()
this._setSelects()
}
/**
*
*/
protected abstract _setSelects()
}
protected _currentEntity: D = null // Set to null and not undefined cause of list.component.html tests for it reason explained https://stackoverflow.com/questions/5076944/what-is-the-difference-between-null-and-undefined-in-javascript
protected abstract displayedColumnsArray: Array<string>; // Gives the order of the columns
public entitiesListTitle = this.constructor.name
// FORMS
entityAddFormGroup: FormGroup;
entityAddFormCtlModelArray: DynamicFormControlModel[];
entityEditFormGroup: FormGroup;
entityEditFormCtlModelArray: DynamicFormControlModel[];
// DATA TABLE variables
dataSource: SseEntityDataSource<D>;
selectionModel = new SelectionModel<D>(true, []);
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
constructor(
protected router: Router,
public messageService: MessageService,
protected logger: LoggerService,
protected route: ActivatedRoute,
protected entitiesService: SseEntityService<D>,
protected formBuilder: FormBuilder,
public formService: DynamicFormService,
iconRegistry: MatIconRegistry,
sanitizer: DomSanitizer,
public entityPrototype: DBEntity,
// private location: Location
) {
super(
iconRegistry,
sanitizer,
)
if (entityPrototype === undefined || entityPrototype == null){
throw new Error('constructor error, create me in the caller entityPrototype!')
}
}
/**
* calls this._getAddFormControlModel() and adds it to entityAddFormCtlModelArray
*/
public ngOnInit() {
// console.debug('ngOnInit called')
if (this.entityPrototype === undefined){
throw new Error('entity-list.component->ngOnInit-> this.entityPrototype is undefined, set it into constructor of descendant')
}
this.entitiesListTitle = StringHelper.camelCaseToSpaces(this.constructor.name.replace('Component', ''))
this.dataSource = new SseEntityDataSource<D>(this.logger, this.entitiesService, this, this.entityPrototype);
this.setMessageService();
this.entityAddFormCtlModelArray = this._getAddFormControlModel(this.entityPrototype);
this.entityAddFormGroup = this.formService.createFormGroup(this.entityAddFormCtlModelArray);
this.dataSource.loadEntities()
}
protected abstract _getCommonFormControlModel(aStrangeObject: DBEntity): DynamicFormControlModel[]
protected abstract _getAddFormControlModel(aStrangeObject: DBEntity): DynamicFormControlModel[]
public ngAfterViewInit() {
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
// this.cdr.detectChanges();
}
get currentEntity(): D {
return this._currentEntity;
}
set currentEntity(value: D) {
this._currentEntity = value;
this.entitiesService.currentEntity = value;
}
/**
* Require dataSource not null
*/
public loadDatasourceWithPaginator() {
// Init currentEntityId
try {
this.dataSource.loadEntities();
} catch (e) {
this.messageService.add(new UserMessage('Error loading entities', e, UserMessageType.Error));
throw e;
}
}
public applyFilter(filterValue: string) {
filterValue = filterValue.trim(); // Remove whitespace
filterValue = filterValue.toLowerCase(); // Datasource defaults to lowercase matches
this.dataSource.filter = filterValue;
}
/**
* Require dataSource not null
*/
public setMessageService() {
this.dataSource.messagesForUsers$.subscribe(
usrMessage => {
this.messageService.add(usrMessage);
}
);
}
abstract onRowClicked(row: any): void;
public buttonAddEntityClicked(dataValues: any) {
console.debug('buttonAddEntityClicked-------->from Entitylist.components dataValues:', dataValues);
let lEntity = this.entityPrototype.deserialize(dataValues, false)
console.debug('buttonAddEntityClicked-------->from Entitylist.components lEntity:', lEntity);
console.debug('buttonAddEntityClicked-------->from Entitylist.components lEntity.toJSON():', lEntity.toJSON());
this.entitiesService.addEntityFromFormData(lEntity.toJSON()).subscribe(
lData => {
const msg = `Entity added successfully`;
this.messageService.add(new UserMessage(msg, lData, UserMessageType.Info));
this.afterEntityUpdatedSucessful()
},
lError => {
const msg = `Entity add Error`;
console.error('buttonAddEntityClicked->Error:', lError)
this.messageService.add(new UserMessage(msg, lError, UserMessageType.Error));
throw lError;
}
);
}
public afterEntityUpdatedSucessful(){
this.loadDatasourceWithPaginator();
}
public buttonEditEntityClicked(jsonStringValues: string) {
this.logger.debug('buttonAddEntityClicked-> from Entitylist.components:', jsonStringValues);
let lEntity = this.entityPrototype.deserialize(jsonStringValues, false)
this.logger.debug('buttonEditEntityClicked-> Entitylist.components: jsonStringValues, lEntity:', jsonStringValues, lEntity);
this.entitiesService.updateEntityFromFormData(lEntity.toJSON()).subscribe(
lData => {
const msg = `Entity updated successfully`;
this.messageService.add(new UserMessage(msg, lData, UserMessageType.Info));
this.afterEntityUpdatedSucessful()
},
lError => {
const msg = `Entity update Error`;
console.error('buttonEditEntityClicked->Error:', lError)
this.messageService.add(new UserMessage(msg, lError, UserMessageType.Error));
throw lError;
}
);
}
public buttonRemoveSelectedRowsClicked() {
let toReloadObservable: Observable<Object> = null;
this.selectionModel.selected.forEach(item => {
this.logger.debug('Deleting selected item:', item);
toReloadObservable = this.entitiesService.deleteFromId(item.id);
toReloadObservable.subscribe(
data => {
const msg = `Entity ${item.id} deleted successfully`;
this.messageService.add(new UserMessage(msg, data, UserMessageType.Info));
this.afterEntityUpdatedSucessful()
},
error => {
const msg = `Error while deleting entity ${item.id}`;
this.messageService.add(new UserMessage(msg, error, UserMessageType.Error));
throw error;
}
);
});
this.selectionModel = new SelectionModel<D>(true, []);
this._currentEntity = null;
// When all are removed reload data source
}
public onReloadClicked(anEvent) {
this.loadDatasourceWithPaginator();
}
public buttonMasterToggleClicked() {
this.isAllSelected() ?
this.selectionModel.clear() :
this.dataSource.data.forEach(row => this.selectionModel.select(row));
}
public sampleAddButtonClicked() {
Constants.SAMPLE_COMPANIES_JSON_DATA.forEach( (entity) => {
// console.log('sampleAddButtonClicked', JSON.stringify(entity));
this.buttonAddEntityClicked(entity);
});
}
public isAllSelected() {
const numSelected = this.selectionModel.selected.length;
const numRows = this.dataSource.entitiesCount();
return numSelected === numRows;
}
protected _updateEditFormFields(toUpdate: any) {
console.log("updateEditFormFields->toUpdate, model", toUpdate, this.entityEditFormCtlModelArray);
Object.entries(toUpdate).forEach(([key, value]) => {
// console.log('updateEditFormFields->setting key', key, 'value:', value);
const inputModel = this.formService.findById(key, this.entityEditFormCtlModelArray) as DynamicInputModel;
if (inputModel == null) {
throw new Error('updateEditFormFields->InputModel is null, key ' + key + ' not found into entityEditFormCtlModel val:' + value );
}
inputModel.valueUpdates.next(value as string)//If not reloading recreate the formGroup with this.entityAddFormGroup = this.formService.createFormGroup(this.entityAddFormCtlModelArray);
// inputModel.valueUpdates.subscribe(value => console.log('new value assigned to field: ', newVal));
// inputModel.disabledUpdates.next(true);
});
}
}
高度相关this post
最佳答案
错误背后的原因:
我认为这个错误与 mat-tab 无关。此错误通常与初始开发阶段相关,其中使用了生命周期 Hook ,如 ngAfterViewInit
。直接引用自 Angular 博客-
This type of error usually shows up beyond the initial development stages, when we start to have some more expressions in our templates, and we have typically started to use some of the lifecycle hooks like AfterViewInit.
不能在 ngAfterViewInit() 中使用分页器引用并立即修改数据源,因为这会触发进一步修改数据,但 Angular View 生成过程尚未完成,因此尚不清楚您在模板中用作表达式的变量应该修改前一个或前一个。
可能的解决方案:
为了解决这个问题,我们需要让Angular先把加载标志设置为false的数据显示出来。
因此,一个可能的解决方案是在 ngAfterViewInit()
中对数据源进行排序之前使用 setTimeOut
或 delay(0)
。
此解决方案有效的原因:
- The initial value of the flag is false, and so the loading indicator will NOT be displayed initially.
ngAfterViewInit()
gets called, but the data source is not immediately called, so no modifications of the loading indicator will be made synchronously viangAfterViewInit()
.Angular then finishes rendering the view and reflects the latest data changes on the screen, and the Javascript VM turn completes.
- One moment later, the
setTimeout()
call (also used insidedelay(0)
) is triggered, and only then the data source loads its data.- the loading flag is set to true, and the loading indicator will now be displayed.
- Angular finishes rendering the view, and reflects the latest changes on the screen, which causes the loading indicator to get displayed.
资源:
要更深入地了解该问题,请查看 this documentation 从我引用的地方。这里用例子来解释整个场景。
你也可以看看this答案,其中 using ngAfterContentInit
代替 ngAfterViewInit
被列为另一种可能的解决方案。
希望对您有所帮助。
更新:
替代解决方案:
正如@jo_va 在评论中提到的,这个问题还有其他可能的解决方案。
代替使用 setTimeOut()
,changeDetector.detectChanges()
也可以使用。
这里我直接根据@jo_va的建议解释:
It could be interesting to mention changeDetector.detectChanges() where changeDector is an injected ChangeDetectorRef. This is another widely used solution to this problem, and I think cleaner than setTimeout.
还有 Promise.resolve
可能是另一种替代方法 设置超时
。
关于angular - 使用 <mat-tab> 时 Angular 6 上的 ExpressionChangedAfterItHasBeenCheckedError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54611631/
SQLite、Content provider 和 Shared Preference 之间的所有已知区别。 但我想知道什么时候需要根据情况使用 SQLite 或 Content Provider 或
警告:我正在使用一个我无法完全控制的后端,所以我正在努力解决 Backbone 中的一些注意事项,这些注意事项可能在其他地方更好地解决......不幸的是,我别无选择,只能在这里处理它们! 所以,我的
我一整天都在挣扎。我的预输入搜索表达式与远程 json 数据完美配合。但是当我尝试使用相同的 json 数据作为预取数据时,建议为空。点击第一个标志后,我收到预定义消息“无法找到任何内容...”,结果
我正在制作一个模拟 NHL 选秀彩票的程序,其中屏幕右侧应该有一个 JTextField,并且在左侧绘制弹跳的选秀球。我创建了一个名为 Ball 的类,它实现了 Runnable,并在我的主 Draf
这个问题已经有答案了: How can I calculate a time span in Java and format the output? (18 个回答) 已关闭 9 年前。 这是我的代码
我有一个 ASP.NET Web API 应用程序在我的本地 IIS 实例上运行。 Web 应用程序配置有 CORS。我调用的 Web API 方法类似于: [POST("/API/{foo}/{ba
我将用户输入的时间和日期作为: DatePicker dp = (DatePicker) findViewById(R.id.datePicker); TimePicker tp = (TimePic
放宽“邻居”的标准是否足够,或者是否有其他标准行动可以采取? 最佳答案 如果所有相邻解决方案都是 Tabu,则听起来您的 Tabu 列表的大小太长或您的释放策略太严格。一个好的 Tabu 列表长度是
我正在阅读来自 cppreference 的代码示例: #include #include #include #include template void print_queue(T& q)
我快疯了,我试图理解工具提示的行为,但没有成功。 1. 第一个问题是当我尝试通过插件(按钮 1)在点击事件中使用它时 -> 如果您转到 Fiddle,您会在“内容”内看到该函数' 每次点击都会调用该属
我在功能组件中有以下代码: const [ folder, setFolder ] = useState([]); const folderData = useContext(FolderContex
我在使用预签名网址和 AFNetworking 3.0 从 S3 获取图像时遇到问题。我可以使用 NSMutableURLRequest 和 NSURLSession 获取图像,但是当我使用 AFHT
我正在使用 Oracle ojdbc 12 和 Java 8 处理 Oracle UCP 管理器的问题。当 UCP 池启动失败时,我希望关闭它创建的连接。 当池初始化期间遇到 ORA-02391:超过
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 9 年前。 Improve
引用这个plunker: https://plnkr.co/edit/GWsbdDWVvBYNMqyxzlLY?p=preview 我在 styles.css 文件和 src/app.ts 文件中指定
为什么我的条形这么细?我尝试将宽度设置为 1,它们变得非常厚。我不知道还能尝试什么。默认厚度为 0.8,这是应该的样子吗? import matplotlib.pyplot as plt import
当我编写时,查询按预期执行: SELECT id, day2.count - day1.count AS diff FROM day1 NATURAL JOIN day2; 但我真正想要的是右连接。当
我有以下时间数据: 0 08/01/16 13:07:46,335437 1 18/02/16 08:40:40,565575 2 14/01/16 22:2
一些背景知识 -我的 NodeJS 服务器在端口 3001 上运行,我的 React 应用程序在端口 3000 上运行。我在 React 应用程序 package.json 中设置了一个代理来代理对端
我面临着一个愚蠢的问题。我试图在我的 Angular 应用程序中延迟加载我的图像,我已经尝试过这个2: 但是他们都设置了 src attr 而不是 data-src,我在这里遗漏了什么吗?保留 d
我是一名优秀的程序员,十分优秀!