【问题标题】:Angular sharing data to Components using service fails使用服务向组件共享数据的角度失败
【发布时间】:2019-03-07 14:26:59
【问题描述】:

我的 Angular 前端中有 2 项服务,一项用于 API 调用,一项用于共享两个不同组件的数据。所以第二个服务是使用API​​服务。

如果我只使用 API 服务并在我的组件中订阅我的 Observables,那么一切正常(在 xxx.component.html 中查看)。

因此,如果我在 app.module 中将这两个服务声明为提供程序,并将 API 服务注入到共享服务中,它将不再起作用。

使用调试器,我总是得到未在 settings.service.ts 中定义的变量“tmp”

我知道,我也可以对子组件使用 @Input 来做到这一点,但我认为使用服务对于解耦组件也是一种更好的方式。

有什么建议吗:)?

在我的代码下方:

api.service.ts

export class ApiService {
    API_URL = 'https://localhost:44381/api/v1';
    constructor(private httpClient: HttpClient) { }

    /** GET settings from API*/
    getSettings(): Observable<Setting[]> {
        return this.httpClient.get<Setting[]>(this.API_URL + '/settings')
        .pipe(
          catchError(this.handleError('getSettings', [])));
    }
}

settings.service.ts

export class SettingsService {

   tmp: Setting[];

   constructor(private apiService: ApiService) { }

   getSettings(): void {
       this.apiService.getSettings()
         .subscribe(settings =>
           this.tmp = settings);
   }

   getData(): Setting[] {
       this.getSettings();
       return this.tmp;
   }
}

settings.component.ts

export class SettingsComponent implements OnInit {
    settings: Setting[];

    constructor(private settingService: SettingsService) { }

    // Load Setting while starting
    ngOnInit() {
        // this.getSettings();
        this.settings = this.settingService.getData();
    }

    // old code when using only API service which works..
    /*getSettings(): void {
        this.apiService.getSettings()
          .subscribe(settings => this.settings = settings);
    }*/
}

settings.component.hmtl

<div>
    <table>
    <tr>
      <th>keyname</th>
      <th>value</th>
      <th>defaultValue</th>
      <th align="right">text</th>
    </tr>

    <tr *ngFor="let s of settings">
      <td>{{s.keyName}}</td>
      <td>{{s.wert}}</td>
      <td>{{s.defaultValue}}</td>
      <td align="right">{{s.description}}</td>
    </tr>
    </table>
</div>

【问题讨论】:

    标签: service dependency-injection angular6 angular-components


    【解决方案1】:

    您的问题在于异步功能。 subscribe 方法用于等待异步操作。这意味着当您执行特定请求(例如远程请求)时,您不希望停止整个流程执行以等待响应。而是您希望在服务器正在处理您的请求并发送它的响应的同时发出请求并执行所有其他代码。

    那么我们来分析一下这段代码执行的流程是怎样的

    getSettings(): void {
           this.apiService.getSettings()
             .subscribe(settings =>
               this.tmp = settings);
       }
    
    getData(): Setting[] {
           this.getSettings();
           return this.tmp;
       }
    
    1. this.getSettings() 执行请求并订阅它 回应
    2. 然后,当它仍在等待订阅响应时,您立即返回 this.tmp,这仍然是未定义的
    3. 在您订阅的请求结束一段时间后,您会获得响应并将该值分配给您的 this.tmp 变量

    如果您已将逻辑拆分为 2 个服务来管理同步问题,请考虑使用主题

    主题的可能解决方案

    服务

    export class SettingsService {
    
       API_URL = 'https://localhost:44381/api/v1';
    
       settingsSource = new Subject<Setting>();
       settings$ = this.settingsSource.asObservable();
    
       constructor(private httpClient: HttpClient) { }
    
       getSettings(): void {
           this.apiService.getSettings().subscribe(settings =>
               this.settingsSource.next(settings);
           );
       }
    
       getData(): Setting[] {
           this.getSettings();
           return this.tmp;
       }
    
       get result$(): Observable<Setting> {
          return this.settings$;
       }
    }
    

    组件

    export class SettingsComponent implements OnInit {
    
        subscription: Subscription;
        settings: Setting[];
    
        constructor(private settingService: SettingsService) { }
    
        // Load Setting while starting
        ngOnInit() {
    
            // subscribe for settings
            this.resSubscription = this.searchService.result$.subscribe(result => {
                this.resList = result.result;
            });
    
            // request settings
            this.settings = this.settingService.getData();
        }
    }
    

    如您所见,SettingsComponent 订阅settings$ Observable$Observable 的约定),然后它会向服务请求数据。 当服务接收到响应数据将它们推送到settingsSource 时,它的Observable 版本(settings$)接收数据并通知所有订阅的组件

    【讨论】:

    • 所以例如所以在服务中使用主题并将它们作为可观察对象返回给组件可能是一个更好的实现?将我的两项服务合并为一项服务是不好的做法吗?
    • 如果您出于某种原因需要它,这不是一个坏习惯。在你的情况下,我找不到真正的原因,但你可以。我会发布一个例子
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多