【发布时间】:2020-06-27 12:48:00
【问题描述】:
我正在编写一个简单的代码来接受一个表单中的几个值并在右侧显示表单值列表。我已经创建了表单字段的模态类,并在提交时将数据发送到服务。在另一个组件中,我订阅了数据。由于某些未知原因,我在第二个组件中的函数被调用了两次。此外,我接受表单中的图像文件或图像 URL,并生成在表单和列表中选择的文件的预览。要在表单中生成此文件的预览,它可以完美运行,但在第二个组件中,相同的代码会进入无限循环。任意
我的主要表单组件 html
<div class="row form">
<div class="col-8">
<form [formGroup]="songMetadata" (submit)="onSubmit(songMetadata)">
<div class="row">
<div class="col form-data">
<mat-form-field>
<mat-label>Song Name</mat-label>
<input matInput formControlName="songName" />
</mat-form-field>
<br />
<br />
<mat-form-field>
<mat-label>Artist Name</mat-label>
<input matInput formControlName="artistName" />
</mat-form-field>
<br />
<br />
<mat-form-field>
<mat-label>Album Name</mat-label>
<input matInput formControlName="albumName" />
</mat-form-field>
<br />
<br />
<mat-form-field>
<mat-label>Spotify URL</mat-label>
<input matInput formControlName="url" />
</mat-form-field>
<br />
<br />
<mat-form-field>
<mat-label>Other Description</mat-label>
<textarea
matInput
formControlName="description"
rows="4"
></textarea>
</mat-form-field>
<br />
<br />
<button
type="submit"
class="btn btn-primary"
[disabled]="
songMetadata.invalid ||
(!isImageFileSelected && !isImageURLEntered)
"
>
Submit
</button>
</div>
<div class="col image-upload">
<div
dropZone
class="text-center dropzone"
(hovered)="changeIsHover($event)"
(dropped)="fileDropped($event)"
[class.hovering]="isHovering"
>
<img
*ngIf="isImageFileSelected || isImageURLEntered"
[src]="imagePreview"
alt=""
width="192"
height="190"
/>
<div
class="drop-text"
*ngIf="!isImageFileSelected && !isImageURLEntered"
>
Drag And Drop File Here
</div>
</div>
<input
type="text"
placeHolder="Or Enter URL"
(blur)="loadPreviewFromURL($event)"
/>
<br />
<label for="files" class="btn btn-primary">Or Select Image</label>
<br />
<input
id="files"
style="visibility:hidden;"
type="file"
(change)="fileSelected($event)"
/>
<br />
<!-- <input type="file" /> -->
</div>
</div>
</form>
</div>
<!-- List View -->
<div class="col-4">
<list></list>
</div>
</div>
主要组件 TS。
import { DataService } from "./data.service";
import { AngularFireStorageModule } from "@angular/fire/storage";
import { Component, OnInit } from "@angular/core";
import { FormGroup, FormBuilder, Validators } from "@angular/forms";
import { Observable } from "rxjs";
import { ISong } from "./song";
import { Data } from "@angular/router";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.scss"]
})
export class AppComponent implements OnInit {
songMetadata: FormGroup;
selectedFile: File = null;
isImageFileSelected: boolean;
isImageURLEntered: boolean;
isHovering: boolean;
song: ISong;
imagePreview: any;
// // Upload Related Stuff
// task: AngularFireUploadTask;
// snapshot: Observable<any>;
constructor(
private formBuilder: FormBuilder,
private service: DataService // private storage: AngularFireStorage
) {
this.isImageFileSelected = false;
this.isHovering = false;
this.isImageURLEntered = false;
}
ngOnInit() {
this.songMetadata = this.formBuilder.group({
songName: ["xzcvzxv", Validators.required],
artistName: ["xzcvcxzv", Validators.required],
albumName: ["zxcvcxv", Validators.required],
url: ["zxcvvc", Validators.required],
description: ["zxcvzcxv", Validators.required]
});
}
fileSelected(event: any) {
this.isImageFileSelected = true;
this.isImageURLEntered = false;
this.selectedFile = event.target.files[0];
this.loadPreview();
}
fileDropped(event: FileList) {
this.isImageFileSelected = true;
this.isImageURLEntered = false;
this.selectedFile = event.item(0);
this.loadPreview();
}
onSubmit(songForm: FormGroup) {
event.preventDefault();
if (this.isImageFileSelected) {
this.song = {
name: songForm.value.songName,
artist: songForm.value.artistName,
album: songForm.value.albumName,
url: songForm.value.url,
description: songForm.value.description,
imageFile: this.selectedFile,
imageURL: null
};
} else {
this.song = {
name: songForm.value.songName,
artist: songForm.value.artistName,
album: songForm.value.albumName,
url: songForm.value.url,
description: songForm.value.description,
imageFile: null,
imageURL: this.imagePreview
};
}
this.service.addSong(this.song);
}
changeIsHover(isHovering: boolean) {
this.isHovering = isHovering;
}
loadPreview = () => {
let reader = new FileReader();
reader.readAsDataURL(this.selectedFile);
reader.onload = event => {
this.imagePreview = reader.result;
};
console.log("PREVIEW HIT");
};
loadPreviewFromURL(event: any) {
console.log(event.target.value);
this.isImageURLEntered = true;
this.isImageFileSelected = false;
this.imagePreview = event.target.value;
}
}
列表组件 HTML
<div *ngFor="let s of songs; let i = index">
<div class="col-4">
<img
*ngIf="s?.imageURL"
[src]="livePrvw(s?.imageURL)"
width="100"
height="100"
alt="Image URL Preview"
/>
<img
*ngIf="s?.imageFile"
[src]="livePreview(s?.imageFile)"
width="100"
height="100"
alt="Image FILE Preview"
/>
</div>
<div class="col-8">
{{ s.name }}
</div>
</div>
listComponent TS
import { DataService } from "./../data.service";
import { ISong } from "./../song";
import { Component, OnInit, OnChanges } from "@angular/core";
@Component({
selector: "list",
templateUrl: "./list.component.html",
styleUrls: ["./list.component.scss"]
})
export class ListComponent implements OnInit {
songs: ISong[];
// song: ISong;
constructor(private service: DataService) {}
ngOnInit() {
this.service.songsAsObservable.subscribe(data => {
this.songs = data;
});
}
// also getting called twice
livePreview(file: File) {
// Going into infinite loop
// let newReader = new FileReader();
// let imagePreview: any;
// newReader.readAsDataURL(file);
// newReader.onload = event => {
// imagePreview = newReader.result;
// };
console.log(file);
}
// getting called twice somehow
livePrvw(imageURL: string) {
console.log(imageURL);
return imageURL;
}
}
重复 ListComponent 中的方法无故被调用两次,并且在 Main Component 中工作的 FileReader 代码在 ListComponent 中不起作用(进入无限循环)
非常感谢任何帮助
【问题讨论】:
-
我建议不要绑定到执行任何繁重处理的函数。在您的情况下,我将创建一个视图模型并预先加载所有数据。然后绑定到歌曲视图模型
-
你现在受制于变化检测周期
-
顺便说一句,最好不要在公共 github 存储库中存储任何敏感信息,例如 firebase 密钥。
-
感谢 Firebase 密钥失误。但其他一切都应该工作。我尝试将 ngOnChanges 放入列表组件中,以查看 onChanges 被触发了多少次,但据我所知,这也被触发了一次,我无法找到对这两个函数的两次调用。还有关于列表组件中无限循环 FileReader 的任何想法?你能在你的机器上运行一次代码,看看它的行为是否不同吗??
-
我认为你最好的选择是在 stackblitz 中使用你目前拥有的抽象代码,用最少的代码重新创建问题
标签: angular typescript angular-services angular-file-upload