Angular2 订阅总是出现空
Angular2 Subscription always comes up null
我有一个我认为相当简单的设置。我正在配置文件输入组件中创建用户配置文件。然后在提交表单并创建用户后,我想将用户发送到 profile-img-upload 组件以添加照片。我的理解是,通过将创建的配置文件保存到配置文件服务中,然后在 img-upload 组件中调用该配置文件,这样做是有意义的。但是我遗漏了一些东西,因为当我到达 img-upload 组件 console.log(this.profile) 时,配置文件始终为空。
我觉得我误解了这里订阅和可观察对象的一些非常核心的东西。我想要做的就是在第一个组件上创建一个配置文件对象,然后将创建的配置文件传递给第二个组件,然后能够上传照片并将其分配给配置文件。
有人可以帮我理解我在这里缺少什么吗?
简介-input.component
import...
@Component({
moduleId: module.id,
selector: 'my-profile-input',
templateUrl: 'profile-input.template.html',
directives: [REACTIVE_FORM_DIRECTIVES]
})
export class ProfileInputComponent implements OnInit {
@Output() profile: Profile;
profile: Profile = null;
constructor(private formBuilder:FormBuilder,
private profileSrevice: ProfileService,
private errorService: ErrorService,
private router: Router,
private route: ActivatedRoute) {}
onSubmit() {
const profile: Profile = new Profile(
this.profileForm.value.first_name,
this.profileForm.value.last_name
);
this.profileSrevice.addProfile(profile)
.subscribe(
data => {
console.log('what comes back from addProfile is: ' + JSON.stringify(data));
this.profileSrevice.profiles.push(data);
// The line below will superceded the one above.
this.profileSrevice.pushData(data);
},
error => this.errorService.handleError(error)
);
this.router.navigate(['profile-img-upload', {myProfile: this.profile}]);
}
profile.service.ts
import...
@Injectable()
export class ProfileService {
pushedData = new EventEmitter<Profile>();
pushData(value: Profile) {
this.pushedData.emit(value);
console.log('value in service is ');
console.log(value);
}
}
profile-img-upload.component.ts
import...
@Component({
moduleId: module.id,
selector: 'my-profile-img-upload',
templateUrl: 'profile-img-upload.template.html',
directives: [ ROUTER_DIRECTIVES, FILE_UPLOAD_DIRECTIVES, NgClass, NgStyle, CORE_DIRECTIVES, FORM_DIRECTIVES ],
providers: [AWSUploadService, UploadFileService]
})
export class ProfileImgUploadComponent implements OnInit {
@Input() myProfile: Profile;
profile: Profile;
constructor(private uploadFileService: UploadFileService,
private route: ActivatedRoute,
private profileService: ProfileService,
private errorService: ErrorService) {
this.filesToUpload = [];}
ngOnInit() {
this.profileService.pushedData.subscribe(
(value: Profile) => this.profile
);
console.log("this.profile in img upload is");
console.log(this.profile);
}
}
您必须将引用从订阅返回的数据的代码移动到订阅回调中。当数据从 observable
到达时调用此回调
ngOnInit() {
this.profileService.pushedData.subscribe(
(value: Profile) => {
this.profile = value;
console.log("this.profile in img upload is");
console.log(this.profile);
});
}
}
我遇到的问题是由于对如何使用可观察对象的误解。我正在重定向到另一个页面(使用新组件重新加载新模板)以从配置文件数据获取我想要上传图像的区域。这是一个有缺陷的概念。我修复它的方法是执行以下操作:
删除用于上传的第二个组件和模板,并将所有该代码合并到配置文件创建组件中
添加一些 ngIf 语句,根据用户完成不同的任务(即输入个人资料信息和创建个人资料对象、添加照片、添加一个视频)。
通过做这些事情,我总是在同一个页面上,所以我可以参考 1 个操作的结果以在另一个操作中使用,并且当事情完成时,我可以设置变量来控制应用程序的状态和正在发生的事情显示给用户。
模板的最终代码如下:
<script src="profile-input.component.ts"></script>
<section class="col-md-8 col-md-offset-2">
<form [hidden]="formSubmitted" [formGroup]="profileForm" (ngSubmit)="onSubmit()">
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label for="first_name">First Name</label>
<input
type="text"
id="first_name"
class="form-control"
formControlName="first_name">
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label for="last_name">Last name</label>
<input
type="text"
id="last_name"
class="form-control"
formControlName="last_name">
</div>
</div>
</div>
<div class="row">
<label>UserType</label>
<input type="checkbox" id="producer" class="form-control" formControlName="producer" >Producer<br>
<input type="checkbox" id="client" class="form-control" formControlName="client" >Client<br>
<input type="checkbox" id="creative" class="form-control" formControlName="creative" >Creative<br>
</div>
<button type="submit" class="btn btn-primary" [disabled]="!profileForm.valid" >{{ !profile ? 'Add Profile' : 'Save Profile' }}</button>
<button type="button" class="btn btn-danger" (click)="onCancel()" *ngIf="profile">Cancel</button>
</form>
</section>
<!-- image upload START-->
<section [hidden]="!imgUploadVisible" class="col-md-8 col-md-offset-2">
<h2 *ngIf="createdProfile">Welcome {{createdProfile.first_name}}!</h2>
<p>Now lets get a look at you.</p>
<hr>
<h2>Profile Image Upload</h2>
<input type="file" (change)="imgFileChangeEvent($event)" placeholder="Upload file..." />
<br>
<button type="button" (click)="uploadImg()">Upload Image</button>
<hr>
<div *ngIf="uploadFile" >
Uploaded File Path: {{ uploadFile }}
</div>
<div class="row">
<div class="col-xs-12">
<div class="img" *ngIf="uploadFile">
<img [src]="uploadFile" width="200px" alt="">
</div>
</div>
</div>
<br>
<button [hidden]="!uploadFile" type="button" (click)="sendToS3()">Send TO S3</button>
<hr>
<div *ngIf="s3LocString">
S3 Location: {{s3LocString}}
<br>
<img [src]="s3LocString" width="200px" alt="">
</div>
<button type="button" (click)="imgUploadComplete()">Next</button>
</section>
<!-- image upload END-->
<!-- Video upload START-->
<section [hidden]="!vidUploadVisible" class="col-md-8 col-md-offset-2">
<h2>Upload Profile Video</h2>
<p>Now show us what you can do.</p>
<hr>
<h2>Demo Video Upload</h2>
<input type="file" (change)="vidFileChangeEvent($event)" placeholder="Upload file..." />
<br>
<button type="button" (click)="uploadVid()">Upload Video</button>
<hr>
<div *ngIf="vidUploadFile" >
Uploaded File Path: {{ vidUploadFile }}
</div>
<div class="row">
<div class="col-xs-12">
<div class="vid" *ngIf="vidUploadFile">
<video autoplay controls [src]="vidUploadFile"></video>
</div>
</div>
</div>
</section>
配置文件输入组件的重要部分如下:
uploadImg() {
console.log('this.createdProfile before upload');
console.log(this.createdProfile);
this.uploadFileService.makeFileRequest("http://localhost:3000/upload", this.createdProfile.profileId, this.imgFilesToUpload, 'profileImg')
.subscribe(
(result) => {
console.log('result in prof input action removed is');
console.log(result);
this.imageUploaded = true;
this.formSubmitted = true;
this.uploadFile = result.obj.path;
this.uploadObject = result.obj
},
(error) => {
console.log('We are in error');
console.error(error);
});
}
uploadVid() {
console.log('this.createdProfile before upload');
console.log(this.createdProfile);
this.uploadFileService.makeFileRequest("http://localhost:3000/upload", this.createdProfile.profileId, this.vidFilesToUpload, 'profileVideo')
.subscribe(
(result) => {
console.log('result in prof input action removed is');
console.log(result);
this.vidUploaded = true;
this.vidUploadFile = result.obj.path;
this.vidUploadObject = result.obj
},
(error) => {
console.log('We are in error');
console.error(error);
});
}
sendToS3() {
console.log('uploading to S3');
console.log(this.uploadObject);
this.uploadFileService.sendToS3(this.uploadObject, this.createdProfile.profileId, this.uploadObject._id)
.subscribe(
data => {
console.log(data);
this.s3Location = data;
this.s3LocString = data.Location;
},
error => {
console.log(error);
}
);
}
希望这可以帮助其他人更好地理解这些概念。
我有一个我认为相当简单的设置。我正在配置文件输入组件中创建用户配置文件。然后在提交表单并创建用户后,我想将用户发送到 profile-img-upload 组件以添加照片。我的理解是,通过将创建的配置文件保存到配置文件服务中,然后在 img-upload 组件中调用该配置文件,这样做是有意义的。但是我遗漏了一些东西,因为当我到达 img-upload 组件 console.log(this.profile) 时,配置文件始终为空。
我觉得我误解了这里订阅和可观察对象的一些非常核心的东西。我想要做的就是在第一个组件上创建一个配置文件对象,然后将创建的配置文件传递给第二个组件,然后能够上传照片并将其分配给配置文件。
有人可以帮我理解我在这里缺少什么吗?
简介-input.component
import...
@Component({
moduleId: module.id,
selector: 'my-profile-input',
templateUrl: 'profile-input.template.html',
directives: [REACTIVE_FORM_DIRECTIVES]
})
export class ProfileInputComponent implements OnInit {
@Output() profile: Profile;
profile: Profile = null;
constructor(private formBuilder:FormBuilder,
private profileSrevice: ProfileService,
private errorService: ErrorService,
private router: Router,
private route: ActivatedRoute) {}
onSubmit() {
const profile: Profile = new Profile(
this.profileForm.value.first_name,
this.profileForm.value.last_name
);
this.profileSrevice.addProfile(profile)
.subscribe(
data => {
console.log('what comes back from addProfile is: ' + JSON.stringify(data));
this.profileSrevice.profiles.push(data);
// The line below will superceded the one above.
this.profileSrevice.pushData(data);
},
error => this.errorService.handleError(error)
);
this.router.navigate(['profile-img-upload', {myProfile: this.profile}]);
}
profile.service.ts
import...
@Injectable()
export class ProfileService {
pushedData = new EventEmitter<Profile>();
pushData(value: Profile) {
this.pushedData.emit(value);
console.log('value in service is ');
console.log(value);
}
}
profile-img-upload.component.ts
import...
@Component({
moduleId: module.id,
selector: 'my-profile-img-upload',
templateUrl: 'profile-img-upload.template.html',
directives: [ ROUTER_DIRECTIVES, FILE_UPLOAD_DIRECTIVES, NgClass, NgStyle, CORE_DIRECTIVES, FORM_DIRECTIVES ],
providers: [AWSUploadService, UploadFileService]
})
export class ProfileImgUploadComponent implements OnInit {
@Input() myProfile: Profile;
profile: Profile;
constructor(private uploadFileService: UploadFileService,
private route: ActivatedRoute,
private profileService: ProfileService,
private errorService: ErrorService) {
this.filesToUpload = [];}
ngOnInit() {
this.profileService.pushedData.subscribe(
(value: Profile) => this.profile
);
console.log("this.profile in img upload is");
console.log(this.profile);
}
}
您必须将引用从订阅返回的数据的代码移动到订阅回调中。当数据从 observable
到达时调用此回调 ngOnInit() {
this.profileService.pushedData.subscribe(
(value: Profile) => {
this.profile = value;
console.log("this.profile in img upload is");
console.log(this.profile);
});
}
}
我遇到的问题是由于对如何使用可观察对象的误解。我正在重定向到另一个页面(使用新组件重新加载新模板)以从配置文件数据获取我想要上传图像的区域。这是一个有缺陷的概念。我修复它的方法是执行以下操作:
删除用于上传的第二个组件和模板,并将所有该代码合并到配置文件创建组件中
添加一些 ngIf 语句,根据用户完成不同的任务(即输入个人资料信息和创建个人资料对象、添加照片、添加一个视频)。
通过做这些事情,我总是在同一个页面上,所以我可以参考 1 个操作的结果以在另一个操作中使用,并且当事情完成时,我可以设置变量来控制应用程序的状态和正在发生的事情显示给用户。
模板的最终代码如下:
<script src="profile-input.component.ts"></script>
<section class="col-md-8 col-md-offset-2">
<form [hidden]="formSubmitted" [formGroup]="profileForm" (ngSubmit)="onSubmit()">
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label for="first_name">First Name</label>
<input
type="text"
id="first_name"
class="form-control"
formControlName="first_name">
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<label for="last_name">Last name</label>
<input
type="text"
id="last_name"
class="form-control"
formControlName="last_name">
</div>
</div>
</div>
<div class="row">
<label>UserType</label>
<input type="checkbox" id="producer" class="form-control" formControlName="producer" >Producer<br>
<input type="checkbox" id="client" class="form-control" formControlName="client" >Client<br>
<input type="checkbox" id="creative" class="form-control" formControlName="creative" >Creative<br>
</div>
<button type="submit" class="btn btn-primary" [disabled]="!profileForm.valid" >{{ !profile ? 'Add Profile' : 'Save Profile' }}</button>
<button type="button" class="btn btn-danger" (click)="onCancel()" *ngIf="profile">Cancel</button>
</form>
</section>
<!-- image upload START-->
<section [hidden]="!imgUploadVisible" class="col-md-8 col-md-offset-2">
<h2 *ngIf="createdProfile">Welcome {{createdProfile.first_name}}!</h2>
<p>Now lets get a look at you.</p>
<hr>
<h2>Profile Image Upload</h2>
<input type="file" (change)="imgFileChangeEvent($event)" placeholder="Upload file..." />
<br>
<button type="button" (click)="uploadImg()">Upload Image</button>
<hr>
<div *ngIf="uploadFile" >
Uploaded File Path: {{ uploadFile }}
</div>
<div class="row">
<div class="col-xs-12">
<div class="img" *ngIf="uploadFile">
<img [src]="uploadFile" width="200px" alt="">
</div>
</div>
</div>
<br>
<button [hidden]="!uploadFile" type="button" (click)="sendToS3()">Send TO S3</button>
<hr>
<div *ngIf="s3LocString">
S3 Location: {{s3LocString}}
<br>
<img [src]="s3LocString" width="200px" alt="">
</div>
<button type="button" (click)="imgUploadComplete()">Next</button>
</section>
<!-- image upload END-->
<!-- Video upload START-->
<section [hidden]="!vidUploadVisible" class="col-md-8 col-md-offset-2">
<h2>Upload Profile Video</h2>
<p>Now show us what you can do.</p>
<hr>
<h2>Demo Video Upload</h2>
<input type="file" (change)="vidFileChangeEvent($event)" placeholder="Upload file..." />
<br>
<button type="button" (click)="uploadVid()">Upload Video</button>
<hr>
<div *ngIf="vidUploadFile" >
Uploaded File Path: {{ vidUploadFile }}
</div>
<div class="row">
<div class="col-xs-12">
<div class="vid" *ngIf="vidUploadFile">
<video autoplay controls [src]="vidUploadFile"></video>
</div>
</div>
</div>
</section>
配置文件输入组件的重要部分如下:
uploadImg() {
console.log('this.createdProfile before upload');
console.log(this.createdProfile);
this.uploadFileService.makeFileRequest("http://localhost:3000/upload", this.createdProfile.profileId, this.imgFilesToUpload, 'profileImg')
.subscribe(
(result) => {
console.log('result in prof input action removed is');
console.log(result);
this.imageUploaded = true;
this.formSubmitted = true;
this.uploadFile = result.obj.path;
this.uploadObject = result.obj
},
(error) => {
console.log('We are in error');
console.error(error);
});
}
uploadVid() {
console.log('this.createdProfile before upload');
console.log(this.createdProfile);
this.uploadFileService.makeFileRequest("http://localhost:3000/upload", this.createdProfile.profileId, this.vidFilesToUpload, 'profileVideo')
.subscribe(
(result) => {
console.log('result in prof input action removed is');
console.log(result);
this.vidUploaded = true;
this.vidUploadFile = result.obj.path;
this.vidUploadObject = result.obj
},
(error) => {
console.log('We are in error');
console.error(error);
});
}
sendToS3() {
console.log('uploading to S3');
console.log(this.uploadObject);
this.uploadFileService.sendToS3(this.uploadObject, this.createdProfile.profileId, this.uploadObject._id)
.subscribe(
data => {
console.log(data);
this.s3Location = data;
this.s3LocString = data.Location;
},
error => {
console.log(error);
}
);
}
希望这可以帮助其他人更好地理解这些概念。