Unable to return observalble value from subscribtion.

huangapple go评论69阅读模式
英文:

Unable to return observalble value from subscribtion

问题

I have been trying to return "students" from my function as an observable, in my code, I am using functions from another service, and these functions return an observable to which I am subscribing. From "classRoom" I am separating students and passing them to another function that returns an array which is then stored in "students".

In the console.log "Log-1" I get the desired output but if I try to return that as an observable or console.log it in "Log-2" it is undefined.

public GetActiveStudents(): Observable<IStudent[]> {
    this.dashboardService.getData().subscribe((res) => {
        this.dashboardService.getDashboardSchools().subscribe((schools) => {
            this.schools = schools;
            this.start = new Date();
            this.end = new Date();
            this.start.setMonth(this.start.getMonth() - 1);

            schools.forEach((school) => {
                this.classRooms = this.classRooms.concat(school.classRooms);
            });

            this.classRooms.forEach((classRoom) => {
                this.students = this.dashboardService.numActiveTwo(this.students.concat(classRoom.students), 'students', this.start, this.end);
            });
            console.log("Log-1" + this.students);
        });
    });
    console.log("Log-2" + this.students);

    return of(this.students)
}
英文:

I have been trying to return "students" from my function as an observable, in my code, I am using functions from another service, and these functions return an observable to which I am subscribing. From "classRoom" I am separating students and passing them to another function that returns an array which is then stored in "students".

In the console.log "Log-1" I get the desired output but if I try to return that as an observable or console.log it in "Log-2" it is undefined.

public GetActiveStudents(): Observable&lt;IStudent[]&gt; {
    this.dashboardService.getData().subscribe((res) =&gt; {
      this.dashboardService.getDashboardSchools().subscribe((schools) =&gt; {
        this.schools = schools;
        this.start = new Date();
        this.end = new Date();
        this.start.setMonth(this.start.getMonth() - 1);

        schools.forEach((schools) =&gt; {
          this.classRooms = this.classRooms.concat(schools.classRooms);
        });

        this.classRooms.forEach((classRoom) =&gt; {
          this.students = this.dashboardService.numActiveTwo(this.students.concat(classRoom.students), &#39;students&#39;, this.start, this.end);
        });
        console.log(&quot;Log-1&quot; + this.students);
      });
    });
    console.log(&quot;Log-2&quot; + this.students);
    
    return of(this.students)
  }

答案1

得分: 2

混合使用可观察对象与设置类变量总是一种混乱的做法。但让我们尝试让它做你想要的事情 :P。

GetActiveStudents(): Observable<IStudent[]> {
  return this.dashboardService.getData().pipe(
    mergeMap((res) => {
      return this.dashboardService.getDashboardSchools().pipe(mergeMap((schools) => {
        this.schools = schools;
        this.start = new Date();
        this.end = new Date();
        this.start.setMonth(this.start.getMonth() - 1);

        schools.forEach((school) => {
          this.classRooms = this.classRooms.concat(school.classRooms);
        });

        this.classRooms.forEach((classRoom) => {
          this.students = this.dashboardService.numActiveTwo(this.students.concat(classRoom.students), 'students', this.start, this.end);
        });
        return of(this.students);
      }));
    })
  );
}

我们做了什么?一般来说,我们使用 mergeMap 来获取下一个可观察对象并将其向上返回,返回的可观察对象在代码中的某个位置订阅之前不执行任何操作。

我鼓励你重新考虑你的代码结构,它将来可能不易维护。尝试以更声明性的方式编写代码,尽量减少对类属性的覆盖(例如,是否真的需要执行 this.start = new Date() ?)。

英文:

Mixing Observables with setting class variables is always a recipe for chaos.
But lets try to get it do what you want :P.

GetActiveStudents(): Observable&lt;IStudent[]&gt; {
  return this.dashboardService.getData().pipe(
    mergeMap((res) =&gt; {
      return this.dashboardService.getDashboardSchools().pipe(mergeMap((schools) =&gt; {
        this.schools = schools;
        this.start = new Date();
        this.end = new Date();
        this.start.setMonth(this.start.getMonth() - 1);

        schools.forEach((schools) =&gt; {
          this.classRooms = this.classRooms.concat(schools.classRooms);
        });

        this.classRooms.forEach((classRoom) =&gt; {
          this.students = this.dashboardService.numActiveTwo(this.students.concat(classRoom.students), &#39;students&#39;, this.start, this.end);
        });
        return of(this.students);
      }));
    })
  );
}

What did we do? In general, we used mergeMap to get to the next Observable and return it upwards, the returned observable does nothing till it gets subscribed somewhere in the code.

I encourage you to overthink the structure of your code, it won't be maintainable in the future. Try it, maybe in a more declarative way and try to not overwrite class properties to reduce side effects.
(for example, is it really necessary to do this.start = new Date() ? )

答案2

得分: 1

Your Log-2 is outside of the subscription, and therefore gets hit before the getDashboardSchools() emits a value. You are also setting the component variable (this.students) in the function while returning the same value as an observable response.

I would suggest you declare and populate a variable in the function and return it as an observable:

public GetActiveStudents(): Observable<IStudent[]> {
    let students: IStudents[] = [];
    
    this.dashboardService.getData().subscribe((res) => {
        this.dashboardService.getDashboardSchools().subscribe((schools) => {
            this.schools = schools;
            this.start = new Date();
            this.end = new Date();
            this.start.setMonth(this.start.getMonth() - 1);

            schools.forEach((school) => {
                this.classRooms = this.classRooms.concat(school.classRooms);
            });

            this.classRooms.forEach((classRoom) => {
                students = this.dashboardService.numActiveTwo(
                    this.students.concat(classRoom.students),
                    'students',
                    this.start,
                    this.end
                );
            });
        });
    });

    return of(students);
}

Then, subscribe to your function in the ngOnInit (or wherever you need it) and set the component variable (this.students) with the value emitted by your observable function:

ngOnInit() {
    this.GetActiveStudents().subscribe(res => {
        this.students = res;
    });
}
英文:

Your Log-2 is outside of the subscription, and therefor gets hit before the getDashboardSchools() emits returns a value. You are also setting the component variable (this.students) in the function, while returning the same value as an observable response.

I would suggest you declare and populate a variable in the function, and return it as an observable:

public GetActiveStudents(): Observable&lt;IStudent[]&gt; {
    this.dashboardService.getData().subscribe((res) =&gt; {
      this.dashboardService.getDashboardSchools().subscribe((schools) =&gt; {
        this.schools = schools;
        this.start = new Date();
        this.end = new Date();
        this.start.setMonth(this.start.getMonth() - 1);
        let students: IStudents[] = [];
        schools.forEach((schools) =&gt; {
          this.classRooms = this.classRooms.concat(schools.classRooms);
        });

        this.classRooms.forEach((classRoom) =&gt; {
          students = this.dashboardService.numActiveTwo(this.students.concat(classRoom.students), &#39;students&#39;, this.start, this.end);
        });

      });
    });
    
    return of(students);
  }

Then, subscribe your function in the ngOnInit (or where ever you need it), and set the component variable (this.students) with the value emitted by your observable function:

ngOnInit()
{
	this.GetActiveStudents().subscribe(res =&gt; {
		this.students = res;
	});
}

答案3

得分: 1

首先,Subscribe工作是异步的。你得到期望的输出是因为console.log "Log-1"被写在subscribe内部,函数必须从subscribe中返回值,所以Log-1包含了期望的输出。但是console.log "Log-2"被写在subscribe外部,这段代码不等待subscribe方法完成,而是在subscribe之后立即执行,所以Log-2的值是undefined。

英文:

First of all Subscribe work as asynchronous. The console.log "Log-1" you are getting the desired output because this is written inside subscribe and the function must return value from subscribe so Log-1 contains desired output but console.log "Log-2" is written outside of subscribe, this code does not wait to complete subscribe method and execute suddenly just after subscribe so value of Log-2 is undefined.

huangapple
  • 本文由 发表于 2023年5月10日 21:02:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76218747.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定