2

Hi i have a function which should return Array, in the below function, this.cordovaFile.readAsArrayBuffer(this.cordovaFile.dataDirectory, storageId) actually returns an Promise Array which i am converting it into Observable and storing into timesheetArray variable and Now timesheetArray it will return Observable array but i just want to return just a Array. Below is the code

Please help, If it return just an array i dont need to change it anywhere , because this function is used through out the application

public getAllTimesheets(): TimesheetModel[] {
  const storageId = TIMESHEET_KEYS.ALL_TIMESHEET;

  const timesheetArray = from(
    this.cordovaFile
    .readAsArrayBuffer(this.cordovaFile.dataDirectory, storageId)
    .then((compressedTimesheet) => {
      const start = moment();
      const uint8array = new Uint8Array(compressedTimesheet);
      const jsonTimeSheet = this.LZString.decompressFromUint8Array(uint8array);
      this.log.debug(`LocalStorageMaterialService: getMaterials() from files: Decompression took ${moment().subtract(start.valueOf()).valueOf()} ms`);
      return <TimesheetModel[] > JSON.parse(jsonTimeSheet) || [];
    })
    .catch((error) => {
      this.log.debug('LocalStorageMaterialService: Retrieving materials from file storage was not possible: ', JSON.stringify(error));
      return [];
    })
  )
  timesheetArray.subscribe((timesheet) => {
    // here how to return an Array ??
  });
}

and just one example why i want to return an array but not observable

let matchedTimesheet = _.find<TimesheetModel>(this.getAllTimesheets() ,
(timesheet) => travelToDate 
&& timesheet.startOfWork.isSame(travelToDate.startDate.value, 'days')
            ); ```

here in the above code it is expecting an array but not Observable., I can do it by subscribing here also , but if the function returns an array instead of  observable, then i need to change everywhere
4
  • Why do you want to return an array instead an observable? How do you want to use your returned array? Commented Jul 9, 2019 at 7:27
  • 1
    You've created a service, ok, within your subscription save a copy of the timesheet to a variable that service clients can access. Your getAllTimesheets() effectively updates the service copy. Or better call next on a BehaviorSubject that clients can subscribe to. Commented Jul 9, 2019 at 7:32
  • @youri i have updated my question in better way, Please check Commented Jul 9, 2019 at 7:42
  • per Sidd's answer const subscription = getAllTimesheets().subscribe(timesheetData => { // Here you'll get that data. let matchedTimesheet = _.find<TimesheetModel>(timesheetData, timesheet) => travelToDate && timesheet.startOfWork.isSame(travelToDate.startDate.value, 'days')); }) Commented Jul 9, 2019 at 7:44

3 Answers 3

2

I don't think you're thinking about this in the correct direction. readAsArrayBuffer is an asynchronous call. Hence it returns a promise.

You shouldn't simply return an TimesheetModel[] from your getAllTimesheets() method.

Rather, you should return an Observable<TimesheetModel[]>. But you'll have to make a small change wherever you're calling this getAllTimesheets() method.

Since it returns an Observable<TimesheetModel[]>, you'll have to either subscribe to getAllTimesheets() at all those places. Or you'll have to read this Observable in your template using the async pipe.

I'd recommend the latter.

So make this following changes to your getAllTimesheets() method.

public getAllTimesheets(): Observable<TimesheetModel[]> {
  const storageId = TIMESHEET_KEYS.ALL_TIMESHEET;
  return from(
    this.cordovaFile
    .readAsArrayBuffer(this.cordovaFile.dataDirectory, storageId)
    .then((compressedTimesheet) => {
      const start = moment();
      const uint8array = new Uint8Array(compressedTimesheet);
      const jsonTimeSheet = this.LZString.decompressFromUint8Array(uint8array);
      this.log.debug(`LocalStorageMaterialService: getMaterials() from files: Decompression took ${moment().subtract(start.valueOf()).valueOf()} ms`);
      return <TimesheetModel[] > JSON.parse(jsonTimeSheet) || [];
    })
    .catch((error) => {
      this.log.debug('LocalStorageMaterialService: Retrieving materials from file storage was not possible: ', JSON.stringify(error));
      return [];
    })
  );
}

And then wherever you're using it, if you're subscribeing to it:

// unsubscribe this subscription on ngOnDestroy()
const subscription = getAllTimesheets()
  .subscribe(timesheetData => {
    // Here you'll get that data.
  })
Sign up to request clarification or add additional context in comments.

Comments

1

Don't register your entire promise as an observable. Setup a BehaviorSubject and update the subject with the result of your promise using .next(). You can then subscribe to that result.

Assuming this is all in a service, you can set this up as follows:

@Injectable({ providedIn: 'root' })
export class TimesheetsService {
  /**
   * Create a new behavior subject with an empty array. This is what you will
   * subscribe to from outside of your service.
   */
  public timesheets$: BehaviorSubject<TimesheetModel[]> = new BehaviorSubject([]);

  constructor() {
    // Call your service method to GET your data.
    this.getAllTimesheets();
  }

  /**
   * This method is how you will update your behavior subject and can be called
   * from outside the service each time you want to update your result.
   */
  public getAllTimesheets() {
    return this.cordovaFile
      .readAsArrayBuffer(this.cordovaFile.dataDirectory, storageId)
      .then((compressedTimesheet) => {
        const uint8array = new Uint8Array(compressedTimesheet);
        const jsonTimeSheet = this.LZString.decompressFromUint8Array(uint8array);
        // On success, update the behavior subject with the result of your call.
        return timesheets$.next(JSON.parse(jsonTimeSheet));
      })
      // Or on error, update the behavior subject.
      .catch(() => timesheets$.next([]));
  }
}

Then in your component you can subscribe to your result$ observable.

export class YourComponent implements OnInit {
  timesheets: TimesheetModel[];

  constructor(private timesheetsService: TimesheetsService) {
    // Optionally call your service method again to GET fresh data.
    this.timesheetsService.getAllTimesheets();
  }

  ngOnInit() {
    /**
     * Subscribe to the result of your service call and pass the result to a
     * reference to be consumed by your component.
     */
    this.timesheetsService.timesheets$
      .subscribe((timesheets) => this.timesheets = timesheets);
  }
}

6 Comments

Can you please check the code again, i have edited it just now, I know that it will execute only after subscribing but how do i return array ?
I have updated my post now that I better understand what you're looking for. BehaviorSubject is the way to go.
Let me try , give me some 15 mins
you are telling me not to use this ? public getAllTimesheets(): TimesheetModel[] { ..}
as i can see in your code, it is still not returning anything and const timesheetArray is un used
|
-1

You can simply use as []

timesheetArray.subscribe((timesheet) => {
    const time_sheet = timesheet as [];
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.