1

In my typescript application, i am having two files say,

File 1 and File 2,

Whereas in File 1, i would like to store a value in localstorage like,

private load() {

return this.entityService
      .load(this.$scope.projectRevisionUid)
      .then(resp => {
        localStorage.removeItem('employeerates');
        this.$scope.employeeRates = resp.employeeRates;
        return this.refreshCostRate(...resp.employeeRates)
          .then(() =>
            localStorage.setItem(
              'employeerates',
              JSON.stringify(this.$scope.employeeRates)
            )
          )
      .then(() => this.refreshBillRate(...resp.employeeRates))
      .then(() => resp.employeeRates.forEach(erm => this.calculate(erm)))
      .then(() => DatepickerUtil.reinitializeDatepickers(this.$scope));
      })

}

In File 2, i am having the following,

          const employeerates = JSON.parse(
            localStorage.getItem('employeerates')
          );

          if (employeerates && employeerates.length != null) {
            employeerates.forEach((element: any) => {
              if (
                this.employee.getUid() === element.user.personUid &&
                element.internalRate
              ) {
                this.cost_rate_uom = element.internalRate * this.uom_factor;
                this.cost_rate_per_hour =
                  this.cost_rate_uom / this.uom_factor;
                this.cost_rate.setValue(this.ap4_cost_rate_per_hour);
              }
            });
          }

Here setting localstorage in File 1 is asynchronous, i am unable to fetch the data at right time in File 2..

Kindly help me to achieve the result of getting localstorage in file 2 without using setTimeOut (because it doesnot solve my issue as i have already checked).

Please help me to pass localstorage value from one file to another which is async..

Update:

I couldn't get any other method of passing the data this.$scope.employeeRates from file 1 to file 2, for which i have used this localstorage method.. So after the async function this.refreshCostRate(...resp.employeeRates) i need to call the localstorage but before that itself my file 2 runs, but above the line this.refreshCostRate(...resp.employeeRates), if i set the localstorage then i am getting localstorage in file 2, but the case is after refresh function only i will get the exact value..

If you suggest any other way of passing data from one ts file to another ts file, then it would also be helpful.. Thing is after this.refreshCostRate(...resp.employeeRates) i will get the exact value for this.$scope.employeeRates which i need to send to file 2..

Maniraj Murugan
  • 8,868
  • 20
  • 67
  • 116
  • But [localStorage is synchronous](https://stackoverflow.com/questions/20231163/is-html5-localstorage-asynchronous)... If it was async, it would take a callback function or at least return a Promise so it could be `await`ed. – Jeremy Thille May 07 '19 at 12:54
  • I am setting the localstorage inside asynchronous, is it wrong method?? – Maniraj Murugan May 07 '19 at 12:56
  • What problem would you solve if `localStorage` were asynchronous? Like Jeremy wrote, it's **synchronous**. Do you know what asynchronous means and what it's used for? – Mjh May 07 '19 at 12:56
  • I couldn't get any other method of passing the data ```this.$scope.employeeRates``` from file 1 to file 2, for which i have used this localstorage method.. So after the async function ```this.refreshCostRate(...resp.employeeRates)``` i need to call the localstorage but before that itself my file 2 runs, but above the line ```this.refreshCostRate(...resp.employeeRates)```, if i set the localstorage then i am getting localstorage in file 2, but the case is after refresh function only i will get the exact value.. – Maniraj Murugan May 07 '19 at 13:00
  • Probably the best you can do is to keep a global variable to hold on to the Promise you create each time you start updating the "employeerates". The Promise that's being returned from `this.refreshCostRate()` would probably work. Then the code in file 2 can just do its work via a `.then()` call on that Promise object. – Pointy May 07 '19 at 13:03
  • 1
    I think we need to rephrase the question. `action` (file1) should trigger a `reaction`. So `localStorage` is not the problem. @sarvon-ks already gave a possible solution, that is to use a custom event, which then can be listened to by file2. Or you could use something like [rxjs](https://www.npmjs.com/package/rxjs). – lumio May 07 '19 at 13:03
  • I don't get the file1 - file2 thing. Where the functions are defined (in which file) is irrelevant. What matters is their order of execution. – Jeremy Thille May 07 '19 at 13:04
  • @lumio yes, that might work, the the answer is about an add-on API. Also, during a period of activity during which the "employerates" data is *not* being updated, what's going to send the events? – Pointy May 07 '19 at 13:04
  • @Pointy, Can you provide a solution with it, as i am unable to get your point.. – Maniraj Murugan May 07 '19 at 13:04
  • @ManirajfromKarur yes give me a moment – Pointy May 07 '19 at 13:05
  • To be clear please give solution with only pure typescript based as because they have used older typescript without rxjs.. – Maniraj Murugan May 07 '19 at 13:06
  • @Pointy thanks for pointing that out. I haven't realize that. – lumio May 07 '19 at 13:06
  • @JeremyThille, Kindly help me with some good solution on handling the thing, After the ```this.refreshCostRate``` only i will get the value but before that itself the function in my file 2 calls, so please help me to get whole value first and then load the function to get those value in another file.. – Maniraj Murugan May 07 '19 at 13:13
  • @ManirajfromKarur I don't know Typescript, but nothing you posted looks like Typescript anyway. – Pointy May 07 '19 at 13:15

2 Answers2

0

Yes we can achieve using storage change event listener

window.addEventListener("storage", ()=>{alert("D")});

https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage/onChanged

sarvon ks
  • 626
  • 3
  • 10
  • I think it would be better to point to a broadly supported API ([e.g. this one](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events) or to another SO answer like [this one](https://stackoverflow.com/questions/24454583/manually-trigger-an-event-on-window-object)) – lumio May 07 '19 at 13:08
0

First, I'm not sure what framework you're using, though since I really don't know any frameworks that wouldn't help me anyway. What I think might work is for the "file 1" code to expose the Promise object created each time that rate table needs to be updated. It's generally considered "bad" to have global variables, and indeed it only has to be globally reachable. As long as code running anywhere in the page can find it, that's good enough; for the example I'll use a global.

So in "file 1" you have:

    localStorage.removeItem('employeerates');
    this.$scope.employeeRates = resp.employeeRates;
    return this.refreshCostRate(...resp.employeeRates)
      .then(() =>
        localStorage.setItem(
          'employeerates',
          JSON.stringify(this.$scope.employeeRates)
        )
      )

That code clears the rate table storage and starts the process to get new rates. What I suggest is to store the Promise in the global:

    localStorage.removeItem('employeerates');
    this.$scope.employeeRates = resp.employeeRates;
    window.employeeRatesPromise = this.refreshCostRate(...resp.employeeRates)
      .then(() =>
        localStorage.setItem(
          'employeerates',
          JSON.stringify(this.$scope.employeeRates)
        )
      );
    return window.employeeRatesPromise;

Now, in "file2", you can do everything as a .then() callback:

    if (window.employeeRatesPromise) {
      window.employeeRatesPromise.then(() => {
        const employeerates = JSON.parse(
          localStorage.getItem('employeerates')
        );

        if (employeerates && employeerates.length != null) {
          employeerates.forEach((element: any) => {
            if (
              this.employee.getUid() === element.user.personUid &&
              element.internalRate
            ) {
              this.cost_rate_uom = element.internalRate * this.uom_factor;
              this.cost_rate_per_hour =
              this.cost_rate_uom / this.uom_factor;
              this.cost_rate.setValue(this.ap4_cost_rate_per_hour);
            }
          });
        }
      else {
        // whatever makes sense when there's no data at all
      }

If the rate table update has completed, then the global Promise will be resolved and the function passed to .then() runs basically immediately. That can happen more than once on the same Promise object. However, when the "file 1" update process is still pending, the "file 2" code will wait for the local storage to be updated. } }

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • Pointy, It displays error as ```Property 'employeeRatesPromise' does not exist on type 'Window'.``` – Maniraj Murugan May 07 '19 at 13:17
  • @ManirajfromKarur OK well like I said, I don't know the context. The point is to have a single globally-accessible place to keep that Promise object. It doesn't matter how you achieve that. – Pointy May 07 '19 at 13:19
  • Okay if i have multiple ```.then()``` after the ```localStorage.setItem()``` then should i need to return the ```return window.employeeRatesPromise;``` after all the ```.then()``` gets completed?? – Maniraj Murugan May 07 '19 at 13:22
  • Return from where? In the "file 1" code I left the `return` there (well changed slightly but it still does the same thing) in case there is other code that depends on it. – Pointy May 07 '19 at 13:26
  • Yes in file 1, i have updated my code in question, you can see lot then after setting localstorage.. – Maniraj Murugan May 07 '19 at 13:29