我的子组件中有一个名为files
的属性,它是input type=file
。使用该属性,我可以检查用户是否选择了要上传的文件,因此如果输入中没有文件,我可以禁用提交按钮。
我的问题是,现在我在父组件中有提交按钮,因此当输入中有文件时,我无法检查属性files
以启用按钮。
那么,如何从父组件访问files属性并检查输入是否包含文件?
我已经尝试使用@ViewChild
装饰器使用类似this.childComponent.files
之类的内容,但我未定义。我也试过了@Output
,但我无法让它发挥作用。
编辑:添加代码
父组件TS:
import { Component, OnInit, ViewChild } from '@angular/core';
import { StepState } from '@covalent/core';
import { StepThreeComponent } from './step-three/step-three.component';
import { StepTwoComponent } from './step-two/step-two.component';
import { StepOneComponent } from './step-one/step-one.component';
@Component({
selector: 'app-user-verification',
templateUrl: './user-verification.component.html',
styleUrls: ['./user-verification.component.scss']
})
export class UserVerificationComponent implements OnInit {
@ViewChild(StepThreeComponent) stepThreeComponent: StepThreeComponent;
@ViewChild(StepTwoComponent) stepTwoComponent: StepTwoComponent;
@ViewChild(StepOneComponent) stepOneComponent: StepOneComponent;
checkFiles: any;
//EXECUTE ALL UPLOAD FUNCTIONS
uploadAllFiles() {
this.stepThreeComponent.uploadSingle();
this.stepOneComponent.uploadSingle();
this.stepTwoComponent.uploadSingle();
console.log('No FUnciona')
}
ngOnInit() {
this.checkFiles = this.stepOneComponent.files;
console.log(this.checkFiles)
}
}
父组件HTML:
<td-steps>
<td-step #step1 sublabel="Suba una copia de la parte delantera de su Cédula de Identidad" [active]="true" [disabled]="false" (activated)="activeStep1Event()" [state]="stateStep1" (deactivated)="deactiveStep1Event()">
<ng-template #head1 td-step-label><span>Foto de Cédula de Identidad (I)</span></ng-template>
<app-step-one></app-step-one>
</td-step>
<td-step #step2 [active]="true" label="Foto de Cédula de Identidad (II)" sublabel="Suba una copia de la parte trasera de su Cédula de Identidad" [state]="stateStep2" [disabled]="false" disableRipple>
<app-step-two></app-step-two>
</td-step>
<td-step #step3 label="Selfie con Cédula de Identidad" sublabel="Subir Selfie" [state]="stateStep3" [disabled]="true" [active]="true">
<app-step-three></app-step-three>
<ng-template td-step-actions>
<button [disabled]="!checkFiles" (click)="uploadAllFiles()">SUBIR TODO</button>
</ng-template>
</td-step>
</td-steps>
儿童组成部分TS:
import { Component } from '@angular/core';
import { UploadService } from '../../../services/upload.service';
import * as firebase from 'firebase/app';
import "firebase/storage";
import { Upload } from '../../../services/upload';
import * as _ from "lodash";
@Component({
selector: 'app-step-one',
templateUrl: './step-one.component.html',
styleUrls: ['./step-one.component.scss']
})
export class StepOneComponent {
selectedFiles: FileList;
currentUpload: Upload;
files: any;
disabled: any;
constructor(private upSvc: UploadService) { }
//Upload Service
detectFiles(event) {
this.selectedFiles = event.target.files;
}
uploadSingle() {
let uid = firebase.auth().currentUser.uid;
let file = this.files
this.currentUpload = new Upload(file);
this.upSvc.pushUpload(this.currentUpload, uid)
}
}
儿童组件HTML:
<div>
<div layout="row">
<md-input-container tdFileDrop [disabled]="disabled" (fileDrop)="files = $event" (click)="fileInput.inputElement.click()" (keyup.enter)="fileInput.inputElement.click()" (keyup.delete)="fileInput.clear()" (keyup.backspace)="fileInput.clear()" flex>
<input mdInput placeholder="select or drop files" [value]="files?.length ? (files?.length + ' files') : files?.name" [disabled]="disabled" readonly/>
</md-input-container>
<button md-icon-button *ngIf="files" (click)="fileInput.clear()" (keyup.enter)="fileInput.clear()">
<md-icon>cancel</md-icon>
</button>
<td-file-input class="push-left-sm push-right-sm" #fileInput [(ngModel)]="files" multiple [disabled]="disabled">
<md-icon>folder</md-icon>
<span class="text-upper">Browse...</span>
</td-file-input>
</div>
<div *ngIf="currentUpload">
<div class="progress">
<div class="progress-bar progress-bar-animated" [ngStyle]="{ 'width': currentUpload?.progress + '%' }"></div>
</div>
Progress: {{currentUpload?.name}} | {{currentUpload?.progress}}% Complete
</div>
</div>
编辑#2:
html parent:
<app-step-one #StepOneComponent></app-step-one>
父母:
ngAfterViewInit() {
this.checkFiles = this.stepOneComponent.getFiles();
}
getFiles() {
this.checkFiles = this.stepOneComponent.getFiles();
console.log(this.checkFiles);
}
ts孩子补充说:
getFiles() {
return this.files
}
我也试过了this.stepOneComponent.files;
,但它也没有用。之后我在子组件中创建getFiles()
以查看是否可以在输入中获取文件并且它有效。我能够从父组件中执行console.log()
并获取文件数据。但我需要做的是自动检查更改,而不是使用按钮内的功能。
编辑#3(重复): 这个问题对我没有帮助,因为我需要自动检查更改而不是手动检查。
答案 0 :(得分:1)
为您的孩子课程提供一些公共元素,例如isValid
,可能还有一些$valid: BehaviorSubject<boolean>
可以通过父组件内的@ViewChild
消费。
@Component({
selector: 'parent-component',
template: '<child-component #childComponent></child-component>'
})
export class ParentComponent implements AfterViewInit {
@ViewChild('childComponent') childComponent: ChildComponent;
ngAfterViewInit(): void {
// do stuff here otherwise your @ViewChildren might not be available
this.childComponent.$valid.subscribe(isValid => {
// do validity related things
})
}
}
编辑:看到你的代码后,我相信你的@ViewChild实现是不正确的:
@ViewChild(StepOneComponent) stepOneComponent: StepOneComponent;
什么都不做。装饰器在用#StepOneComponent
装饰的父组件标记中找不到任何内容。
在您的标记中,您需要:
<app-step-one #StepOneComponent></app-step-one>
在你的班上:
@ViewChild('StepOneComponent') stepOneComponent: StepOneComponent;
编辑更多内容:
@ViewChild('thisIsADecorator') someVariableName: SomeComponentClass;
是指向:
的指针<child-component #thisIsADecorator></child-component>
哪个是SomeComponentClass
的实例,其选择器为child-component
。您需要使用AfterViewInit的原因是子组件将不可用; from Angular's docs:
ngAfterViewInit()在Angular初始化组件的视图和子视图后做出响应。
在您的父类中,@ViewChild(StepOneComponent) stepOneComponent: StepOneComponent;
没有做任何事情。
您的父母标记:
<td-steps>
<td-step #step1 sublabel="Suba una copia de la parte delantera de su Cédula de Identidad" [active]="true" [disabled]="false" (activated)="activeStep1Event()" [state]="stateStep1" (deactivated)="deactiveStep1Event()">
<ng-template #head1 td-step-label><span>Foto de Cédula de Identidad (I)</span></ng-template>
<app-step-one></app-step-one>// <---- This is the view child you're trying to get a handle on, but there is nothing for Angular to use to find it
</td-step>
如果你解决了这些问题,那么你所做的就会奏效。
用于暴露属性getter的编辑
这里的诀窍在于,您td-file-input
与ngModel
绑定了files
中的属性StepOneComponent
。为了让自己适应变化倾听者,您需要做的就是利用files
的getter / setter。
private _files: any;
private $_files: BehaviorSubject<any> = new BehaviorSubject();
public get files(): any {
return this._files;
}
public set files(val: any) {
this.$_files.next(this._files = val);
}
public get $files(): Observable<any> {
return this.$_files.asObservable();
}
然后在您的父组件中:
ngAfterViewInit() { // <-- I would really switch to this from ngOnInit
this.stepOneComponent.$files.subscribe((newVal: any) => {
console.log(newVal);
// do stuff
});
}