APP_INITIALIZER not awaiting (Angular 13) - javascript

I am in the process of updating from okta/okta-angular 3.x to 5.x. It seems to have introduced an odd bug.
When the app first starts up, we have been using APP_INITIALIZER to execute appInitializerFactory(configService: ConfigService), which makes an http call to load configuration data.
The call looks like this:
public async loadConfig(): Promise<any> {
return this.httpClient.get('assets/config.json').pipe(settings => settings)
.toPromise()
.then(settings => {
this.config = settings as IAppConfig;
})
.catch(exception => {
console.log("Exception encountered while retreiving configuration");
});
}
Before updating to okta 5.x, the APP_INITIALIZER has been awaiting the promise. Now, it appears that other providers are being resolved before the promise in APP_INITILIZER has finished.
The resulting issue happens downstream at the oktaInitializerFactory, where it runs the following code:
public oktaConfig() {
return Object.assign({
onAuthRequired: (oktaAuth: OktaAuth, injector: Injector) => {
const router = injector.get(Router);
router.navigate(['/login']);
}
}, this.config.oktaConfig);
}
On the last line, this.config.oktaConfig is returning as undefined because the APP_INITIALIZER has not finished awaiting.
Heres the complete app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { Routes, RouterModule, Router } from '#angular/router';
import { APP_INITIALIZER, NgModule } from '#angular/core';
import { MaterialModule } from './modules/material/material.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import { TablesComponent } from './components/tables/tables.component';
import { PageNotFoundComponent } from './components/page-not-found/page-not-found.component';
import { DashboardComponent } from './components/dashboard/dashboard.component';
import { ToolbarComponent } from './components/toolbar/toolbar.component';
import { LoginComponent } from './components/login/login.component';
import { FormsModule } from '#angular/forms';
import { RunLogComponent } from './components/run-log/run-log.component';
import { RunDataComponent } from './components/run-data/run-data.component';
import { ActionComponent } from './components/action/action.component';
import { ErrorsComponent } from './components/errors/errors.component';
import { OktaAuth } from '#okta/okta-auth-js';
import { OKTA_CONFIG, OktaAuthGuard, OktaAuthModule, OktaCallbackComponent } from '#okta/okta-angular';
import { HttpClientModule, HTTP_INTERCEPTORS } from '#angular/common/http';
import { TabulatorUserTableComponent } from './components/tabulator-user-table/tabulator-user-table.component';
import { TabulatorTableComponent } from './components/tabulator-table/tabulator-table.component';
import { DataLakeComponent } from './components/data-lake/data-lake.component';
import { IntegrationHistoryComponent } from './components/integration-history/integration-history.component';
import { IntegrationStatusComponent } from './components/integration-status/integration-status.component';
import { MatSpinnerButtonComponent } from './components/mat-spinner-button/mat-spinner-button.component';
import { ConfigService } from './services/config.service';
import { DataStudioComponent } from './components/data-studio/data-studio.component';
import { IntegrationDashboardComponent } from './components/integration-dashboard/integration-dashboard.component';
import { IntegrationSelectorToolbarComponent } from './integration-selector-toolbar/integration-selector-toolbar.component';
import { PrimaryButtonsComponent } from './components/primary-buttons/primary-buttons.component';
import { UserCardComponent } from './components/user-card/user-card.component';
import { HttpOktaInterceptorService } from './services/http-okta-interceptor.service';
import { DebugInfoComponent } from './components/debug-info/debug-info.component';
import { ModalModule } from './modal';
import { DragNDrop } from './components/dropbox/drag-n-drop';
import { ProgressComponent } from './components/dropbox/progress/progress.component';
const appRoutes: Routes = [
{
path: '',
component: DashboardComponent,
canActivate: [OktaAuthGuard]
},
{
path: 'login/callback',
component: OktaCallbackComponent
},
{
path: 'login',
component: LoginComponent
}
];
#NgModule({
declarations: [
AppComponent,
TablesComponent,
PageNotFoundComponent,
DashboardComponent,
ToolbarComponent,
LoginComponent,
RunLogComponent,
RunDataComponent,
ActionComponent,
ErrorsComponent,
TabulatorUserTableComponent,
TabulatorTableComponent,
DataLakeComponent,
IntegrationHistoryComponent,
IntegrationStatusComponent,
MatSpinnerButtonComponent,
DataStudioComponent,
IntegrationDashboardComponent,
IntegrationSelectorToolbarComponent,
PrimaryButtonsComponent,
UserCardComponent,
DebugInfoComponent,
ProgressComponent,
DragNDrop
],
imports: [
BrowserModule,
OktaAuthModule,
RouterModule.forRoot(appRoutes, { relativeLinkResolution: 'legacy' }),
BrowserAnimationsModule,
MaterialModule,
FormsModule,
HttpClientModule,
ModalModule
],
providers: [
{
provide: APP_INITIALIZER,
useFactory: appInitializerFactory,
deps:[ConfigService],
multi: true
},
{
provide: OKTA_CONFIG,
useFactory: oktaInitializerFactory,
deps:[ConfigService],
},
{
provide: HTTP_INTERCEPTORS,
useClass: HttpOktaInterceptorService,
multi: true,
deps: [OktaAuth]
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
export function appInitializerFactory(configService: ConfigService) {
return () => configService.loadConfig();
}
export function oktaInitializerFactory(configService: ConfigService) {
return configService.oktaConfig();
}
Is there a particular reason why my APP_INITIALIZER isn't finishing before other code executes? When I downgrade back to okta 3.x, this issue goes away.

As it turns out, upgrading from Okta 3 to 4+ or 5+ does introduce a change that makes loading auth server configuration in APP_INITIALIZER a non-viable option.
In a nutshell, okta-angular will attempt to connect to the auth server before the APP_INITIALIZER finishes. The workaround for this is to load the configuration data into the injector in main.ts, which fires off before the APP_INITIALIZER. This technically goes against the documentation in angular.io, but Okta support has verified this behavior [Source]
Another user does a similar implementation for Auth0, which encountered the same problem, linked here: stackoverflow.com/a/66957293/3202440

I have no idea how it was supposed to work in previous versions. you have appInitializerFactory that depends on ConfigService. ConfigService depends on HttpClient. HttpClient => HTTP_INTERCEPTORS i.e. on HttpOktaInterceptorService. HttpOktaInterceptorService => OktaAuth which most likely relies on OKTA_CONFIG.
It means that to construct a HttpClient(which is implicitly requried for initializer) you need OKTA_CONFIG already constructed. and it sounds very logical that this config initializer is being called earlier than APP_INITIALIZERs.
Most likely this dependency was introduced during refactoring, not just the update.
In your place I would try to eliminate dependency on a HttpClient in ConfigService and just make this request with a native api

Related

Angularfire Appcheck not initialized correctly

I am using the angular fire 7.3 (modular) and is really unclear how to setup Appcheck. I am gettin a "Missing or insufficient permissions." error and as I immagined Appcheck is blocking all calls for storage and firestore.
I have seen the code sample here
and have configure the enviroment variables like shown here
I have configured the app module similarly to how they suggested to do here, except that I am not using emulators
but it still acts as if the initialization didn't go through for what concerns Appcheck, both locally and on the deployed version. (both localhost and the domain have been regisred on recaptcha)
Obviously the recaptcha V3 site key I used is correct and has been setup on firebase as well. I did it before on a previous React project which at least for that part worked similarly but at least requests were going through.
...What am I missing?
I saw there is a post showing to essentially initialize firebase like you would do without angularfire but this would end up in having 2 firebase apps running and this sounds really hacky and suboptimal.
I wish their documentation said something about Appcheck...
app-module:
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { MenuComponent } from './components/menu/menu.component';
import { LayoutComponent } from './components/layout/layout.component';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import {MatIconModule} from "#angular/material/icon";
import { HeroComponent } from './components/hero/hero.component';
import { PagenotfoundComponent } from './components/pagenotfound/pagenotfound.component';
import {RouterModule} from "#angular/router";
import { initializeApp,provideFirebaseApp } from '#angular/fire/app';
import { environment } from '../environments/environment';
import { provideAnalytics,getAnalytics,ScreenTrackingService,UserTrackingService } from '#angular/fire/analytics';
import { provideAuth,getAuth } from '#angular/fire/auth';
import { provideFirestore,getFirestore } from '#angular/fire/firestore';
import { provideFunctions,getFunctions } from '#angular/fire/functions';
import { provideStorage,getStorage } from '#angular/fire/storage';
import { LoginComponent } from './components/login/login.component';
import { AppcheckComponent } from './components/appcheck/appcheck.component';
import { ReleaseComponent } from './components/release/release.component';
import { PreloadComponent } from './components/preload/preload.component';
let resolvePersistenceEnabled: (enabled: boolean) => void;
export const persistenceEnabled = new Promise<boolean>(resolve => {
resolvePersistenceEnabled = resolve;
});
#NgModule({
declarations: [
AppComponent,
MenuComponent,
LayoutComponent,
HeroComponent,
PagenotfoundComponent,
LoginComponent,
AppcheckComponent,
ReleaseComponent,
PreloadComponent,
],
imports: [
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
MatIconModule,
provideFirebaseApp(() => initializeApp(environment.firebase)),
provideAnalytics(() => getAnalytics()),
provideAuth(() => getAuth()),
provideFirestore(() => getFirestore()),
provideFunctions(() => getFunctions()),
provideStorage(() => getStorage()),
],
providers: [
ScreenTrackingService,UserTrackingService
],
bootstrap: [AppComponent]
})
export class AppModule { }
appcheck-component
import { Component, OnInit } from '#angular/core';
import { getToken, AppCheck } from '#angular/fire/app-check';
import { traceUntilFirst } from '#angular/fire/performance';
import { EMPTY, from, Observable } from 'rxjs';
import { keepUnstableUntilFirst } from '#angular/fire';
import { share } from 'rxjs/operators';
#Component({
selector: 'app-app-check',
template: `
<p>
App Check!
<code>{{ (change$ | async)?.token | slice:0:12 }}<ng-container *ngIf="(change$ | async) !== null">…</ng-container></code>
</p>
`,
styles: []
})
export class AppcheckComponent implements OnInit {
readonly change$: Observable<any>;
constructor(appCheck: AppCheck) {
if (appCheck) {
this.change$ = from(getToken(appCheck)).pipe(
traceUntilFirst('app-check'),
keepUnstableUntilFirst,
share(),
);
} else {
this.change$ = EMPTY;
}
}
ngOnInit(): void {
}
}
enviroment variables
export const environment = {
firebase: {
apiKey: "...",
authDomain: "...",
projectId: "...",
storageBucket: "...",
messagingSenderId: "...",
appId: "...",
measurementId: "..."
},
recaptcha3SiteKey: '...',
production: false
};
Version Info:
Anglular 13.1
Firebase 9.8
AngularFire 7.3 (modular)
Just add the AppCheck provider to AppModule imports as you did with all the other ones (Firestore, Functions, etc).
import { initializeAppCheck, provideAppCheck, ReCaptchaV3Provider } from '#angular/fire/app-check'
...
provideAppCheck(() =>
initializeAppCheck(undefined, {
provider: new ReCaptchaV3Provider(environment.recaptchaSiteKey),
isTokenAutoRefreshEnabled: true,
})
),

Why angular is not recognizing if a user is logged in with keycloak?

So I'm trying to set up a sso system with keycloak on my angular app.
I have downloaded the keycloak library keycloak-angular#4.0.2, setted up a keycloak server at localhost:8080/auth, added the keycloak.json on the root of the app, that keycloak made for me:
{
"realm": "my-app",
"auth-server-url": "http://localhost:8080/auth",
"ssl-required": "external",
"resource": "my-app",
"public-client": true,
"confidential-port": 0
}
Also I added the keycloak initi function in the main.ts:
import { enableProdMode } from '#angular/core';
//....some other import....
import { KeycloakService } from 'keycloak-angular';
var injector = ReflectiveInjector.resolveAndCreate([KeycloakService]);
var keycloak = injector.get(KeycloakService)
if (environment.production) {
enableProdMode();
}
keycloak.init()
.then(() => platformBrowserDynamic().bootstrapModule(AppModule))
.catch(e => {
console.error(e);
});
Now, if I try to make a registration page, something like this:
export class registration implements OnInit {
constructor(keycloak:KeycloakService) {
keycloak.register();
}
ngOnInit() {
}
}
It works and sends me to a registration page and if I create an account it appears in the keycloak server.
BUT... even if I am not logged in with any account it lets me access any page, also, if I try:
keycloak.isLoggedIn().then(() => console.log("logged"), ()=>console.log("Not logged"));
The result is "logged", but if I try:
keycloak.loadUserProfile();
Then it says
The user profile was not loaded as the user is not logged in.
I can't understand how it works, am I missing something?
So my question is:
- How do I prevent pages to show if I am not logged in?
- How do I make a user log and stay logged and angular to recognize who is logged and who is not.
UPDATE: As asked I'm adding app.module.ts
import { BrowserModule, HAMMER_GESTURE_CONFIG } from '#angular/platform-browser';
import { NgModule, APP_INITIALIZER } from '#angular/core';
import { TranslateModule } from '#ngx-translate/core';
import { HttpClientModule } from '#angular/common/http';
import { KeycloakService, KeycloakAngularModule } from 'keycloak-angular';
import { initializer } from './utils/app-init';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { AuthenticationModule } from './core/auth/authentication.module';
import { NgxPermissionsModule } from 'ngx-permissions';
import { LayoutModule } from './content/layout/layout.module';
import { PartialsModule } from './content/partials/partials.module';
import { CoreModule } from './core/core.module';
import { AclService } from './core/services/acl.service';
import { LayoutConfigService } from './core/services/layout-config.service';
import { MenuConfigService } from './core/services/menu-config.service';
import { PageConfigService } from './core/services/page-config.service';
import { UserService } from './core/services/user.service';
import { UtilsService } from './core/services/utils.service';
import { ClassInitService } from './core/services/class-init.service';
import { NgbModule } from '#ng-bootstrap/ng-bootstrap';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import { GestureConfig, MatProgressSpinnerModule } from '#angular/material';
import { OverlayModule } from '#angular/cdk/overlay';
import { MessengerService } from './core/services/messenger.service';
import { ClipboardService } from './core/services/clipboard.sevice';
import { PERFECT_SCROLLBAR_CONFIG, PerfectScrollbarConfigInterface } from 'ngx-perfect-scrollbar';
import { LayoutConfigStorageService } from './core/services/layout-config-storage.service';
import { LogsService } from './core/services/logs.service';
import { QuickSearchService } from './core/services/quick-search.service';
import { SubheaderService } from './core/services/layout/subheader.service';
import { HeaderService } from './core/services/layout/header.service';
import { MenuHorizontalService } from './core/services/layout/menu-horizontal.service';
import { MenuAsideService } from './core/services/layout/menu-aside.service';
import { LayoutRefService } from './core/services/layout/layout-ref.service';
import { SplashScreenService } from './core/services/splash-screen.service';
import { DataTableService } from './core/services/datatable.service';
import 'hammerjs';
import { AppAuthGuardComponent } from './utils/keycloak/app-auth-guard/app-auth-guard.component';
import { KEYCLOAK_HTTP_PROVIDER } from './utils/keycloak/keycloak.http';
const DEFAULT_PERFECT_SCROLLBAR_CONFIG: PerfectScrollbarConfigInterface = {
// suppressScrollX: true
};
#NgModule({
declarations: [AppComponent, AppAuthGuardComponent],
imports: [
BrowserAnimationsModule,
BrowserModule,
AppRoutingModule,
HttpClientModule,
LayoutModule,
PartialsModule,
CoreModule,
OverlayModule,
AuthenticationModule,
NgxPermissionsModule.forRoot(),
NgbModule.forRoot(),
TranslateModule.forRoot(),
MatProgressSpinnerModule,
KeycloakAngularModule,
],
providers: [
AclService,
LayoutConfigService,
LayoutConfigStorageService,
LayoutRefService,
MenuConfigService,
PageConfigService,
UserService,
UtilsService,
ClassInitService,
MessengerService,
ClipboardService,
LogsService,
QuickSearchService,
DataTableService,
SplashScreenService,
KeycloakService,
KEYCLOAK_HTTP_PROVIDER,
{
provide: PERFECT_SCROLLBAR_CONFIG,
useValue: DEFAULT_PERFECT_SCROLLBAR_CONFIG
},
{
provide: APP_INITIALIZER,
useFactory: initializer,
multi: true,
deps: [KeycloakService]
},
// template services
SubheaderService,
HeaderService,
MenuHorizontalService,
MenuAsideService,
{
provide: HAMMER_GESTURE_CONFIG,
useClass: GestureConfig
}
],
bootstrap: [AppComponent]
})
export class AppModule {
}
Check and add loadUserProfileAtStartUp: true, to the init config,
mine was like below, and It has resolved the issue for me,
export function initializer(keycloak: KeycloakService): () => Promise {
return (): Promise => {
return new Promise(async (resolve, reject) => {
try {
await keycloak.init({
config: {
url: environment.keycloak.issuer,
realm: environment.keycloak.realm,
clientId: environment.keycloak.clientId
},
loadUserProfileAtStartUp: true,
initOptions: {
onLoad: 'check-sso',
checkLoginIframe: true
},
bearerExcludedUrls: []
});
resolve(1);
} catch (error) {
reject(error);
}
});
};
}

Error at angular CLI production build

I am trying to build the angular version 5 application for production with this command of angular cli version 1.5.2:
ng build --prod
but it gives me this error :
ERROR in Error: Error encountered resolving symbol values statically. Calling fu nction 'FlashMessagesModule', function calls are not supported. Consider replaci ng the function or lambda with a reference to an exported function, resolving sy mbol AppModule in D:/Project/mean-auth-app/angular-src/src/app/app.module.ts, re solving symbol AppModule in D:/Project/mean-auth-app/angular-src/src/app/app.mod ule.ts
It seems angular v5.0 has a conflict with angular2-flash-messages module version 2.0.0.
I did exactly the same thing here to install and setup the flash messages module. I searched but i couldn't find any useful hint. Some people call it a bug and some people could solve their problem with uninstall/install the problematic package.
My app module :
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { RouterModule, Routes } from '#angular/router';
import { HttpModule } from '#angular/http';
import { AppComponent } from './app.component';
import { NavbarComponent } from './components/navbar/navbar.component';
import { LoginComponent } from './components/login/login.component';
import { RegisterComponent } from './components/register/register.component';
import { HomeComponent } from './components/home/home.component';
import { DashboardComponent } from './components/dashboard/dashboard.component';
import { ProfileComponent } from './components/profile/profile.component';
import { AccountService } from './services/account.service';
import { FlashMessagesModule } from 'angular2-flash-messages';
import { JwtModule } from '#auth0/angular-jwt';
import { HttpClientModule } from '#angular/common/http';
import { AuthGuard } from './services/auth-guard.service';
const routes = [
{ path: '', component: HomeComponent },
{ path: 'register', component: RegisterComponent },
{ path: 'login', component: LoginComponent },
{ path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard]},
{ path: 'profile', component: ProfileComponent, canActivate: [AuthGuard]}
];
#NgModule({
declarations: [
AppComponent,
NavbarComponent,
LoginComponent,
RegisterComponent,
HomeComponent,
DashboardComponent,
ProfileComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
FlashMessagesModule.forRoot(),
RouterModule.forRoot(routes),
HttpClientModule,
JwtModule.forRoot({
config: {
tokenGetter: () => {
return localStorage.getItem('token');
},
whitelistedDomains: ['localhost:4200']
}
})
],
providers: [AccountService, AuthGuard],
bootstrap: [AppComponent]
})
export class AppModule { }
I appreciate any hint to solve this problem.
EDIT: The following will also break the --prod build, but the message marks another problem.
I took a look at the angular2-flash-messages package and the error lies in their code:
They don't add the required metadata of the angular compiler.
There is no solution until following issue is fixed: https://github.com/moff/angular2-flash-messages/issues/31
Old answer:
You aren't allowed to use lambda functions in a decorator.
The error lies here:
config: {
tokenGetter: () => { // <- here
return localStorage.getItem('token');
},
whitelistedDomains: ['localhost:4200']
}
The problem is, that angular will not be able to store all required informations about the decorator if you use a lambda function, but an exported function can be used.
You have to rewrite it to:
export function tokenGetter() {
return localStorage.getItem('token');
}
And you should be able to use it like this in your code:
config: {
tokenGetter: tokenGetter,
whitelistedDomains: ['localhost:4200']
}
Specifying paths to #angular inside AngularCLI's tsconfig.json prevented the error from happening.
"paths": { "#angular/*": ["../node_modules/#angular/*"] }
Reference : link

Setting up and inserting data in PouchDb on Ionic 2

Hi Guys im completely new to Ionic 2,
But i know js/ts and all that fun stuff already. Now i want to use PouchDb in my ionic app here is my home.ts file:
import { Component } from '#angular/core';
import * as PouchDB from 'pouchdb';
import cordovaSqlitePlugin from 'pouchdb-adapter-cordova-sqlite';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
}
PouchDB.plugin(cordovaSqlitePlugin);
var db = new PouchDB('test', { adapter: 'cordova-sqlite' });
function setData(data) {
var todo = {
title: data,
completed: false
};
db.post(todo, function callback(err, result) {
if (!err) {
console.log('Successfully posted a todo!');
}
});
}
function getData() {
console.log(db.allDocs);
}
Here is my first problem var db = new PouchDb....is no fuction when I put in a on startup function i get an error because my "setData" function doesnt know what "db" is. How can i fix that? And is my importing stuff right?
Next question do i have to import that stuff in my app.module.ts file too? an do i need a provider?
import { NgModule, ErrorHandler } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { AboutPage } from '../pages/about/about';
import { ContactPage } from '../pages/contact/contact';
import { HomePage } from '../pages/home/home';
import { TabsPage } from '../pages/tabs/tabs';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
#NgModule({
declarations: [
MyApp,
AboutPage,
ContactPage,
HomePage,
TabsPage
],
imports: [
BrowserModule,
IonicModule.forRoot(MyApp),
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
AboutPage,
ContactPage,
HomePage,
TabsPage
],
providers: [
StatusBar,
SplashScreen,
{provide: ErrorHandler, useClass: IonicErrorHandler}]
})
export class AppModule {}
I think thats everything for now. Thank you for your help
First, you need to install the SQLite provider.
Here is a tutorial for setting up the PouchDb In Ionic Using SQLite as the database.
https://gonehybrid.com/how-to-use-pouchdb-sqlite-for-local-storage-in-ionic-2/
If you need more help, just comment and I will improve the answer.

How can I use Electron's webview html element inside an angular2 template?

I saw this question: How to use Electron's <webview> within Angular2 app?
And it got me past my initial error but now I'm seeing
zone.js?1478729974810:355 Unhandled Promise rejection: Template parse errors:
'webview' is not a known element:
1. If 'webview' is an Angular component, then verify that it is part of this module.
2. If 'webview' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '#NgModule.schemas' of this component to suppress this message. ("url" [src]="paper.url | path" [original-size]="false" [show-all]="true"></pdf-viewer-->
[ERROR ->]<webview id="inlinePaper" attr.src="{{paper.url | path}}" disablewebsecurity></webview>
</div"): PaperComponent#45:12 ; Zone: <root> ; Task: Promise.then ; Value: Error: Template parse errors:(…) Error: Template parse errors:
'webview' is not a known element:
1. If 'webview' is an Angular component, then verify that it is part of this module.
2. If 'webview' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '#NgModule.schemas' of this component to suppress this message. ("url" [src]="paper.url | path" [original-size]="false" [show-all]="true"></pdf-viewer-->
[ERROR ->]<webview id="inlinePaper" attr.src="{{paper.url | path}}" disablewebsecurity></webview>
</div"): PaperComponent#45:12
at TemplateParser.parse (http://localhost:5555/node_modules/#angular/compiler/bundles/compiler.umd.js:7711:21)
at RuntimeCompiler._compileTemplate (http://localhost:5555/node_modules/#angular/compiler/bundles/compiler.umd.js:17193:53)
at eval (http://localhost:5555/node_modules/#angular/compiler/bundles/compiler.umd.js:17098:85)
at Set.forEach (native)
at compile (http://localhost:5555/node_modules/#angular/compiler/bundles/compiler.umd.js:17098:49)
at ZoneDelegate.invoke (http://localhost:5555/node_modules/zone.js/dist/zone.js?1478729974810:203:28)
at Zone.run (http://localhost:5555/node_modules/zone.js/dist/zone.js?1478729974810:96:43)
at http://localhost:5555/node_modules/zone.js/dist/zone.js?1478729974810:462:57
at ZoneDelegate.invokeTask (http://localhost:5555/node_modules/zone.js/dist/zone.js?1478729974810:236:37)
at Zone.runTask (http://localhost:5555/node_modules/zone.js/dist/zone.js?1478729974810:136:47)
I added CUSTOM_ELEMENTS_SCHEMA to both my root module and the other module in play here as well as trying the NO_ERRORS_SCHEMA described in the angular documentation for NgModule but I'm still seeing this same template error.
This project has a lot of files and I won't list them all here but feel free to ask for whatever you might feel relevant.
This was built from the angular2 advanced seed at https://github.com/NathanWalker/angular-seed-advanced
My root module 'web.module.ts':
// angular
import { NgModule, NO_ERRORS_SCHEMA } from '#angular/core';
import { APP_BASE_HREF } from '#angular/common';
import { BrowserModule } from '#angular/platform-browser';
import { RouterModule } from '#angular/router';
import { Http } from '#angular/http';
// libs
import { StoreModule } from '#ngrx/store';
import { EffectsModule } from '#ngrx/effects';
import { TranslateLoader } from 'ng2-translate';
// app
import { AppComponent } from './app/components/app.component';
import { ToolbarComponent } from './app/components/toolbar/toolbar.component';
import { HomeComponent } from './app/components/home/home.component';
import { routes } from './app/components/app.routes';
// feature modules
import { CoreModule } from './app/frameworks/core/core.module';
import { AnalyticsModule } from './app/frameworks/analytics/analytics.module';
import { multilingualReducer, MultilingualEffects } from './app/frameworks/i18n/index';
import { MultilingualModule, translateFactory } from './app/frameworks/i18n/multilingual.module';
import { SampleModule } from './app/frameworks/sample/sample.module';
import { EventModule } from './app/components/event/event.module';
// config
import { Config, WindowService, ConsoleService, EventService } from './app/frameworks/core/index';
Config.PLATFORM_TARGET = Config.PLATFORMS.WEB;
if (String('<%= ENV %>') === 'dev') {
// only output console logging in dev mode
Config.DEBUG.LEVEL_4 = true;
}
// sample config (extra)
import { AppConfig } from './app/frameworks/sample/services/app-config';
import { MultilingualService } from './app/frameworks/i18n/services/multilingual.service';
// custom i18n language support
MultilingualService.SUPPORTED_LANGUAGES = AppConfig.SUPPORTED_LANGUAGES;
let routerModule = RouterModule.forRoot(routes);
if (String('<%= TARGET_DESKTOP %>') === 'true') {
Config.PLATFORM_TARGET = Config.PLATFORMS.DESKTOP;
// desktop (electron) must use hash
routerModule = RouterModule.forRoot(routes, {useHash: true});
}
declare var window, console;
// For AoT compilation to work:
export function win() {
return window;
}
export function cons() {
return console;
}
#NgModule({
imports: [
BrowserModule,
CoreModule.forRoot([
{ provide: WindowService, useFactory: (win) },
{ provide: ConsoleService, useFactory: (cons) }
]),
routerModule,
AnalyticsModule,
MultilingualModule.forRoot([{
provide: TranslateLoader,
deps: [Http],
useFactory: (translateFactory)
}]),
StoreModule.provideStore({
i18n: multilingualReducer,
}),
EventModule
],
declarations: [
AppComponent,
HomeComponent,
ToolbarComponent
],
providers: [
{
provide: APP_BASE_HREF,
useValue: '<%= APP_BASE %>'
},
EventService
],
bootstrap: [AppComponent],
schemas: [NO_ERRORS_SCHEMA]
})
export class WebModule { }
Here is my sub module the event module:
// angular
import { NgModule, ModuleWithProviders, Optional, SkipSelf, NO_ERRORS_SCHEMA } from '#angular/core';
import { CommonModule } from '#angular/common';
import { FormsModule } from '#angular/forms';
import { RouterModule } from '#angular/router';
import { HttpModule } from '#angular/http';
import { eventComponent } from './event.component';
import { EventDetailsComponent } from './details/event.details.component';
import { EventNavigationComponent } from './navigation/event.navigation.component';
import { EventAlphanavComponent } from './navigation/event.alphanav.component';
import { EventTrackComponent } from './index-track/event.track.component';
import { EventScheduleComponent } from './index-schedule/event.schedule.component';
import { EventAlphaComponent } from './index-alpha/event.alpha.component';
import { EventAuthorComponent } from './index-author/event.author.component';
import { EventAuthorListComponent } from './index-author/list/event.author.list.component';
import { EventSponsorComponent } from './sponsors/event.sponsor.component';
import { EventExhibitorComponent } from './exhibitors/event.exhibitor.component';
import { EventActivitiesComponent } from './activities/event.activities.component';
import { PaperComponent } from './paper/paper.component';
// libs
import { StoreModule } from '#ngrx/store';
// app
import { Config, WindowService, ConsoleService, EventService, Path } from '../../frameworks/core/index';
// state
/**
* Do not specify providers for modules that might be imported by a lazy loaded module.
*/
#NgModule({
imports: [
CommonModule,
HttpModule,
RouterModule,
StoreModule
],
schemas: [ NO_ERRORS_SCHEMA ],
declarations: [
eventComponent,
EventDetailsComponent,
EventNavigationComponent,
EventAlphanavComponent,
EventTrackComponent,
EventScheduleComponent,
EventAlphaComponent,
EventAuthorComponent,
EventAuthorListComponent,
EventSponsorComponent,
EventExhibitorComponent,
EventActivitiesComponent,
PaperComponent,
Path
]
})
export class EventModule {
constructor(#Optional() #SkipSelf() parentModule: EventModule) {
if (parentModule) {
throw new Error('SampleModule already loaded; Import in root module only.');
}
}
}
Any clue what I'm doing wrong here? Will this even work once I have this template problem worked out?
Any direction at all is appreciated. I'm following what instructions I can find but it's still not working. Thanks in advance!
Create a dummy directive for webview.
import { Directive } from '#angular/core';
#Directive({
selector: 'webview'
})
/** Dummy directive to allow html-tag 'webview' */
export class WebviewDirective {}
and add it to your AppModule declarations array:
...
import { WebviewDirective } from './webview.directive';
#NgModule({
imports: [...],
declarations: [..., WebviewDirective],
providers: [...],
bootstrap: [...]
})
export class AppModule {}
Credits to Philipp for his answer: https://stackoverflow.com/a/39290383/6028371
There must have been some problem with my testing. The above code worked after rebuilding the project and the webview element does what it needs to do in the electron context.

Categories

Resources