简体   繁体   English

BehaviorSubject 在变量改变时不执行

[英]BehaviorSubject doesn't execute when the variable changes

I am not sure if I understand the usage of a BehaviorSubject , but what I want to do is watch a variable for change, and this variable is a two-way binding variable attached to <input type="file"> .我不确定我是否理解BehaviorSubject的用法,但我想要做的是观察一个变量的变化,这个变量是一个附加到<input type="file">的双向绑定变量 When the input changes I want to execute a function that will automatically upload the file.当输入更改时,我想执行一个自动上传文件的函数。

<input type="file" [(ngModel)]="presentationService.fileSelected">

The component I am using looks like this:我正在使用的组件如下所示:

@Component({
    selector: '...',
    templateUrl: '...'
})
export class CreatePresentationStep1 {
    public constructor(public presentationService: PresentationService) { }
}

The service looks like this:该服务如下所示:

@Injectable()
export class PresentationService {
    public fileSelected?: File;

    public constructor() {
        this.handlers();
    }

    private handlers(): void {
        new BehaviorSubject<File>(this.fileSelected).subscribe({
            next: (file) => {
                console.log('file', file);
            }
        });
    }
}

When the component loads, the console log runs and prints file undefined , which is correct.当组件加载时,控制台日志运行并打印file undefined ,这是正确的。 When I click on the input field and select a file, the behavior never runs again.当我单击输入字段并选择一个文件时,该行为再也不会运行。 Is that intended?这是故意的吗? I would expect the call to run again since the variable changed.由于变量更改,我希望调用再次运行。 How can I get my behavior to run every time the variable changes?每次变量更改时,如何让我的行为运行?

That's not really how a BehaviorSubject works.这并不是BehaviorSubject的真正工作方式。 What you pass in the constructor is just the default initial value.您在构造函数中传递的只是默认初始值。 It cannot monitor a property.它无法监控资产。 In your case, this code should work:在您的情况下,此代码应该有效:

<input type="file" [ngModel]="presentationService.fileSelected$ | async" 
       (ngModelChange)="presentationService.fileSelected$.next($event)">

@Component({
    selector: '...',
    templateUrl: '...'
})
export class CreatePresentationStep1 {
  constructor(public presentationService: PresentationService) { }
}

@Injectable()
export class PresentationService {
    public readonly fileSelected$ = new BehaviorSubject<File | void>(void 0);

    public constructor(private _httpClient: HttpClient) {
        this.handlers();
    }

    private handlers(): void {
      this.fileSelected$.subscribe({
        next: (file) => {
          console.log('file', file);
        }
      });
    }
}

Although this is not entirely like I would do it.虽然这并不完全像我会做的那样。 This gives consumers of your PresentationService full access to the subject/observable, but it's one way :)这使PresentationService消费者可以完全访问主题/可观察对象,但这是一种方式:)

Try this:尝试这个:

<input type="file" (change)="fileChangeEvent($event)">

Bind event listener in component:在组件中绑定事件监听器:

@Component({
    selector: '...',
    templateUrl: '...'
})
export class CreatePresentationStep1 {
    public constructor(public presentationService: PresentationService) { }
    public fileChangeEvent(fileInput: any) {
      const file = fileInput.target.files[0];
      this.presentationService.handlers(file).subscribe(file => console.log('file', file));
   }
}

And in Service:并在服务中:

@Injectable()
export class PresentationService {
    public fileSelected?: File;
    private handlersSubject= new BehaviorSubject<File>(undefined);
    public handlerObs$ = this.handlersSubject.asObservable();

    public handlers(file: any): void {
        this.handlersSubject.next(file);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM