Angular 7:服务实例无法正常工作

时间:2020-05-16 04:51:14

标签: angular typescript angular7 angular-services behaviorsubject

我的应用程序中有两个组件-“过滤器”和“家”。这两个组件是应用程序组件的子组件。

我有一个我要通过服务从过滤器组件传递到家庭组件的以下对象。而且,由于我希望每当过滤器组件发生更改时就在home组件中更新这些数据,因此我在服务中使用BehaviorSubject。

型号:filter-response.model.ts

export interface FilterResponse{
    filter:string;
    filterlist:string[];
}

filter.component.ts

export class FilterComponent implements OnInit {
    filterMainList:FilterResponse[]=[
        {
            "filter": "abc",
            "filterlist": ["a","b","c"]
        },
        {
            "filter": "def",
            "filterlist":["d","e","f"]
        },
        {
            "filter": "ghi",
            "filterlist": ["g","h","i"]
        }
    ];
    constructor(private filterService:FilterService,) {
        this.filterService.setFilterConditions(this.filterMainList);
    }
    ngOnInit() {
    }
}

在家庭组件中,我收到了数据,我想对其进行一些更改。

home.component.ts

export class HomeComponent implements OnInit {
  constructor(private filterService:FilterService) {
    this.filterService.getFilterConditions().subscribe((data)=>{
      let tc:FilterResponse[]=data
      for(let f in tc){
        tc[f].filterlist=['changes'];//this is where I make the changes
      }
    });
   }
  ngOnInit() {
  }
}

我有一个包含行为主题的过滤器服务。这就是我感到困惑的地方。我将数据记录在服务中next()之前的服务中,而我实际获得的数据是我在home组件中更改的,这意味着我对home组件中的数据实例所做的更改也影响(更改)了服务中的数据。

filter.service.ts

@Injectable({
    providedIn:'root'
})
export class FilterService{
    private filterConditions = new BehaviorSubject<FilterResponse[]>(null);
    constructor(){}
    setFilterConditions(filterList:FilterResponse[]){
        console.log(filterList);//data changes incorrectly
        this.filterConditions.next(filterList);
    }
    getFilterConditions():Observable<FilterResponse[]>{
        return this.filterConditions.asObservable();        
    }
}

我的控制台日志:

console log

实际上应该是我刚刚在过滤器组件中传递的数据。但它会显示我在家庭组件中修改的数据。

如果有帮助的话,最后是app.component.ts

app.component.ts

<app-filter></app-filter>
<app-home></app-home>

我想提醒您的另一件事是。我试图在stackblitz中重新创建方案。但是问题在于它在这里工作正常。

https://stackblitz.com/edit/angular-ivy-9th5pj

请解释一下我在项目中缺少的内容。还是这是服务将按角度工作的实际方式。

3 个答案:

答案 0 :(得分:2)

在您的服务文件中进行此更改

 setFilterConditions(filterList:FilterResponse[]){
    this.filterConditions.next(JSON.parse(JSON.stringify(filterList)));
}

这将克隆您的阵列。还有很多其他方法可以在JS中克隆对象/数组 Different ways to Clone object in JS

原因

在TS中,将对象作为函数参数传递时,您正在传递对该对象的引用。因此,在修改传递给函数的对象时,您就是在修改原始对象。

类似地,通过引用接收在 HomeComponent 的订阅函数中接收的数组/对象。因此, HomeComponent 中的值更改也会在服务中受到影响。

答案 1 :(得分:2)

我误解了您的问题:我想您的问题是,为什么console.log输出在修改后 之前显示修改后的数组。

就像khush's answer中解释的那样,非原始类型通过引用传递:JS不会将数组的副本传递给函数/方法,而是传递数组本身。因此,这就是filterMainList传递的数组实例(next),并且在您的HomeComponent中对其进行了修改。

现在,在修改数据之前您有console.log(filterList),但是日志输出仍然显示更改。这是因为当您在浏览器的控制台中单击Array(3)时,调试器此时将评估变量的值,该值此时已被修改。

这在您的stackblitz示例中不可见,因为您没有记录数组,而是JSON.stringify(arr)。在这种情况下,您无需在控制台中扩展该值,该值已经显示为字符串,并且不会重新评估。 如果我们仅记录变量,则stackblitz demo将重现相同的“问题”

如果这种行为不是所希望的,则可以克隆按照khush的建议传递的数据;可以从发送它的组件中获得,也可以直接在服务中调用next之前,如果代码中多次调用setFilterConditions

,则只需执行一次

答案 2 :(得分:0)

我只想扩展库什的回答。因此,如果创建深层副本无济于事,则可以从loadash中使用cloneDeep函数。在最坏的情况下(修复程序问题),请使用此选项。 由于浅拷贝而发生此问题。 因此,在每种情况下返回数组时,都不会返回新数组,而是返回数组的地址。因此,阵列将发生任何变化,原始阵列也会发生变化。而且,当您使用JSON.stringigy或deepClone函数时,会在内部创建具有不同地址的数组副本

setFilterConditions(filterList:FilterResponse[]){
    this.filterConditions.next(cloneDeep(filterList));
}