Alorel / ngforage

localForage bindings for Angular
https://alorel.github.io/ngforage/
MIT License
111 stars 18 forks source link

Compilation error Angular 7 and 8 in AoT #107

Open RomainMarecat opened 5 years ago

RomainMarecat commented 5 years ago

npm i
npm run build

ERROR in Error during template compile of 'AppModule' Function calls are not supported in decorators but 'NgForageModule' was called.

Additional information, screenshots etc go here.

Alorel commented 5 years ago

Yeah, I've gotten this bug too but I have no idea why after hours of debugging and trying out various solutions by people with similar issues. At the moment it appears to be a regression from Angular 6 as the module hasn't changed (4.0.0 | 3.4.0).

If you have any solutions do let me know please!

You can get around it for now, though. NgForage consists only of services, so importing the module isn't actually necessary; you can simply perform the default configuration in your AppModule's constructor:

import {BrowserModule} from '@angular/core';
import {NgForageConfig} from 'ngforage';

@NgModule({imports: [BrowserModule]})
export class AppModule {
  public constructor(ngfConfig: NgForageConfig) {
    ngfConfig.configure(configurationOptions);
  }
}

Issue reported here: https://github.com/angular/angular/issues/23609#issuecomment-433450395

Dedme commented 5 years ago

Since moving to Angular 7 and then needing to apply the workaround from @Alorel, i am having the issue of my dedicated instance factory which was only changing the store is now no longer picking up my config from the app module.

export class AppModule {
  public constructor(ngfConfig: NgForageConfig) { 
    ngfConfig.configure({
      name: 'DatabaseName1',
      storeName: 'App',
      driver: [
        Driver.INDEXED_DB,
        Driver.WEB_SQL,
        Driver.LOCAL_STORAGE
      ]
    });
  }
 }

requests made using the standard import works fine, and saves to this database in the LocalDB however in one of my services i have:

private ngfw: NgForage;

  constructor(private http: HttpClient, private userOptions: UserOptionsService, 
              ngfdif: DedicatedInstanceFactory) {
    this.ngfw = ngfdif.createNgForage({storeName: 'Other'});
  }

all requests made to the ngfw are being saved to ngForage Database not the DatabaseName1

Alorel commented 5 years ago

@Dedme I can't seem to reproduce the error.

app.module.ts

@NgModule({
  imports:      [ 
    BrowserModule
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { 
  public constructor(ngfc: NgForageConfig) {
    ngfc.configure({
      name: 'mamc',
      driver: [
        Driver.LOCAL_STORAGE
      ]
    });
  }
}

app.component.ts

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular';

  public constructor(private readonly diFactory: DedicatedInstanceFactory) {
    const ngf = diFactory.createNgForage({name: 'eyy'});
    console.dir(ngf);
    // finalCOnfig correctly shows name as 'eyy' and driver as [localstorage]
  }
}

I understand that this is a messier solution than the one that was available for ng6, but we have to work with what we can, unfortunately. I've made the injection token provided by NgForageModule.forRoot() exported and non-internal in ngforage 4.0.1, allowing you to achieve forRoot() functionality without actually calling forRoot():

import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {DEFAULT_CONFIG, NgForageOptions} from 'ngforage';

const ngfRootOptions: NgForageOptions = {
  name: 'DatabaseName1',
  // ... other config options
};

@NgModule({
  imports: [BrowserModule],
  providers: [{
    provide: DEFAULT_CONFIG,
    useValue: ngfRootOptions
  }]
})
export class AppModule {}

Can you try that out and let me know if it solves your issue please? I'll then update the README accordingly.

Dedme commented 5 years ago
import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {DEFAULT_CONFIG, NgForageOptions} from 'ngforage';

const ngfRootOptions: NgForageOptions = {
  name: 'DatabaseName1',
  // ... other config options
};

@NgModule({
  imports: [BrowserModule],
  providers: [{
    provide: DEFAULT_CONFIG,
    useValue: ngfRootOptions
  }]
})
export class AppModule {}

Can you try that out and let me know if it solves your issue please? I'll then update the README accordingly.

Thanks for this. works great!!! i did realise i had ngforage being imported as a provider in my appmodule, but after removing this is still had my same issue.

also without using the provider method, which i am perfectly okay with as it seems to be the new standard that i am seeing everywhere, i did end up with an empty 'ngforage' database. so it seemed to be getting initialised before the constructor could set its config.

thanks for the fast feedback!

quen2404 commented 5 years ago

Same issue for me... Thanks for your workaround @Alorel !

weronikasabiniewicz commented 5 years ago

Hi everyone!

I have a problem with AOT compilation in Angular 7.1. I have tried config ngForage in both of presenting ways. The first was into it in AppModule constructor, and second one as a provider (with DEFULT_CONFIG). Unfortunately, when I use ngForage:

ngOnInit(){ this.forage.storeName = 'MyStorage; this.forage.setItem('key','value'); }

forage is NgForage as Dependency Injection in the constructor.

During the building isn't any errors. Then, after load the website, I have a one error in the console:

image

This happened only if I have built it with aot option.

Do you know what I am doing wrong? Or is there any workaround?

Alorel commented 5 years ago

@weronikasabiniewicz I'm terribly sorry, this is embarrassing, but I completely missed your reply... I wasn't able to reproduce your issue - have you set the library up exactly as stated in the instructions? Do you have localforage installed? Perhaps you misconfigured something? I generated a new project with the CLI, tried your ngOnInit, and everything worked fine.

app.component.ts:

import {ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit} from '@angular/core';
import {NgForage} from 'ngforage';

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
  public ngfValue: string;

  public constructor(
    private readonly ngf: NgForage,
    private readonly cdr: ChangeDetectorRef
  ) {
  }

  public ngOnInit() {
    const k = 'ngf-test-date-value';
    this.ngf.storeName = 'ngf-test-date-store';
    this.ngf.setItem(k, new Date().toLocaleString())
      .then(() => this.ngf.getItem<string>(k))
      .then(v => {
        this.ngfValue = v;
        this.cdr.markForCheck();

        return this.ngf.removeItem(k);
      })
      .catch(console.error);
  }
}

app.component.html:

<div *ngIf="ngfValue; else default">Ngforage returned {{ngfValue}}</div>
<ng-template #default>Loading</ng-template>

app.module.ts:

// unmodified

Could you create a repo that reproduces the issue on https://stackblitz.com and create a separate issue please?

Alorel commented 5 years ago

I've tried reproducing the initial AOT compilation issue in the upcoming Angular 8 PR and, unfortunately, the issue is still there with no updates from the Angular team apart from "this'll get fixed with Ivy" (which wasn't fully released with Angular 8 yet).

luckyboykg commented 5 years ago

Should I use this solution as a workaround at this time?

Changes in app.module.ts:

import {Driver, NgForageOptions, DEFAULT_CONFIG} from 'ngforage';

...

const ngfRootOptions:NgForageOptions = {
  name: 'next-storage',
  driver: [
    Driver.INDEXED_DB,
    Driver.WEB_SQL,
    Driver.LOCAL_STORAGE
  ]
};

...

providers: [
    {
      provide:  DEFAULT_CONFIG,
      useValue: ngfRootOptions
    }
    ...
]
...

Source: https://stackoverflow.com/a/56741945/1979190

weronikasabiniewicz commented 5 years ago

@weronikasabiniewicz I'm terribly sorry, this is embarrassing, but I completely missed your reply... I wasn't able to reproduce your issue - have you set the library up exactly as stated in the instructions? Do you have localforage installed? Perhaps you misconfigured something? I generated a new project with the CLI, tried your ngOnInit, and everything worked fine.

app.component.ts:

import {ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit} from '@angular/core';
import {NgForage} from 'ngforage';

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
  public ngfValue: string;

  public constructor(
    private readonly ngf: NgForage,
    private readonly cdr: ChangeDetectorRef
  ) {
  }

  public ngOnInit() {
    const k = 'ngf-test-date-value';
    this.ngf.storeName = 'ngf-test-date-store';
    this.ngf.setItem(k, new Date().toLocaleString())
      .then(() => this.ngf.getItem<string>(k))
      .then(v => {
        this.ngfValue = v;
        this.cdr.markForCheck();

        return this.ngf.removeItem(k);
      })
      .catch(console.error);
  }
}

app.component.html:

<div *ngIf="ngfValue; else default">Ngforage returned {{ngfValue}}</div>
<ng-template #default>Loading</ng-template>

app.module.ts:

// unmodified

Could you create a repo that reproduces the issue on https://stackblitz.com and create a separate issue please?

@Alorel Hi,

I have created code on https://stackblitz.com and it looks fine. I have to check my old code written in Angular 7.1 and I will back to you.

Thanks for response.

Alorel commented 5 years ago

Should I use this solution as a workaround at this time?

Changes in app.module.ts:

import {Driver, NgForageOptions, DEFAULT_CONFIG} from 'ngforage';

...

const ngfRootOptions:NgForageOptions = {
  name: 'next-storage',
  driver: [
    Driver.INDEXED_DB,
    Driver.WEB_SQL,
    Driver.LOCAL_STORAGE
  ]
};

...

providers: [
    {
      provide:  DEFAULT_CONFIG,
      useValue: ngfRootOptions
    }
    ...
]
...

Source: stackoverflow.com/a/56741945/1979190

Yeah, to give a recap, this issue was a regression in Angular when moving from ng6 to ng7 even though nothing had changed in this library. It was supposed to get fixed with the Ivy compiler, but that still hasn't arrived so we need to provide the configuration at the moment. If the issue persists in Angular 9, I'll just remove the forRoot API.

sagits commented 4 years ago

Hi guys the DEFAULT_CONFIGexporting is missing when installing through npm install localforage@^1.5.0 ngforage@^4.0.0 # Angular 7 (I've checked the files and the export is really missing).

Solved by using npm install ngforage@ng7.