Bootstrapping hybrid AngularJS & Angular application causing very slow rendering - javascript

I'm currently trying to bootstrap a large Angular 1.6.1 app to Angular 4.0.1 using the UpgradeModule. I've managed to successfully get the app to run, but I've noticed a significant slowdown with rendering times - so bad that it completely freezes after triggering a few events.
I suspect that it is an issue with the digest loop, and running the profiler I can see that the zonejs function calls are taking a very long time to process.
It's also unclear whether I should expect significantly slower rendering times whilst running a hybrid app?
I've also noticed some odd behaviour that may be related to the same issue. The promises seem to be working inconsistently. It seems like server responses are successfully returning, but the angular promises doesn't detect that it has returned - resulting in an infinite loading icon (I have a loader component which displays a loading icon until ALL promises have returned).
Is there anything in particular I could check for, that may be causing the slow rendering?
Here is my set up.
app.ts - main entry file
import 'zone.js';
import 'reflect-metadata';
import { NgModule } from '#angular/core';
import { UpgradeModule } from '#angular/upgrade/static';
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule } from './main.module';
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
upgrade.bootstrap(document.body, ['main']);
});
main.module.ajs.ts - my AngularJS module (I've removed all dependencies for readability)
// AngularJS entry
import './exampleDep/exampleDep.module';
import { CONFIGURATION } from '../config';
angular
.module('main', [
'ngRoute',
'exampleDep'
])
.config(applicationRouting)
.run(applicationInit)
.constant('CONFIGURATION', CONFIGURATION);
function applicationInit($rootScope, CONFIGURATION) {
$rootScope.CONFIGURATION = CONFIGURATION;
}
function applicationRouting($routeProvider, $analyticsProvider) {
$analyticsProvider.firstPageview(false);
$analyticsProvider.virtualPageviews(false);
$routeProvider
.when('/?', {
reloadOnSearch: false
})
.otherwise({
redirectTo: '/'
});
}
main.module.ts - my Angular module
// Angular entry
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { UpgradeModule } from '#angular/upgrade/static';
#NgModule({
imports: [
BrowserModule,
UpgradeModule
],
bootstrap: []
})
export class AppModule {
ngDoBootstrap() {}
}

Related

Angular structure loaded both synchronously and asynchronously when adding primeng tableModule

I had the following error when loading TableModule from primeng into my components module file and trying to run 'npm run packagr':
Maximum call stack size exceeded
I found this solution, to change my primeng version primeng12 to primeng11.4.5. So I did that, but now I am getting the following error:
Angular structure loaded both synchronously and asynchronously
This is my components module file:
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { HeaderComponent } from './header.component';
import { TableModule } from 'primeng/table';
#NgModule({
declarations: [HeaderComponent],
imports: [CommonModule, TableModule],
exports: [HeaderComponent],
})
export class HeaderModule {} //RED LINE APPEARS HERE UNDER HEADERMODULE, BUT NOWHERE ELSE
Does anyone have any ideas how I can fix this?
Fixed this by changing prime ng version to 9.1.3 and installing angular cdk

Lazy Loading Angular / Ionic 3 Component AOT "is not a known element: Error"

This is driving me crazy, hopefully someone can shed some light on the problem. I am Lazy loading my Ionic components everything works fine in development, however when I go to compile AOT throws an error. I spent about 4 hours trying different ways to load this in I am lost, keep getting the same error.
From what I read and found in examples this should be correct. What am I missing here?
'tester' is not a known element: 1. If 'tester' is an Angular component, then verify that it is part of this
module. 2. To allow any element add 'NO_ERRORS_SCHEMA' to the '#NgModule.schemas' of this component. ("
<ion-list *ngIf="!id"> <ion-list-header> [ERROR -><tester></tester>
// components/tester/tester.ts
import { Component } from '#angular/core';
#Component({
selector: 'tester',
templateUrl: 'tester.html'
})
export class TesterComponent {
text: string;
constructor() {
console.log('Hello TesterComponent Component');
this.text = 'Hello World';
}
}
// components/components.module.ts
import { NgModule } from '#angular/core';
import { TesterComponent } from './tester/tester';
import {IonicModule} from "ionic-angular";
#NgModule({
declarations: [TesterComponent],
imports: [IonicModule],
exports: [TesterComponent,
]
})
export class ComponentsModule {}
// pages/faq/faq.module.ts
import { NgModule } from '#angular/core';
import { IonicPageModule } from 'ionic-angular';
import { FaqPage } from './faq';
import {ComponentsModule} from "../../components/components.module";
#NgModule({
declarations: [
FaqPage
],
imports: [
IonicPageModule.forChild(FaqPage), ComponentsModule
],
})
export class FaqPageModule {}
// pages/faq/faq.html
<tester></tester>
EDIT
Thanks to #Joel Joseph - Apparently the view needs to reside in the same directory as your parent component. I had the view .html file in a shared directory hence the problem.
templateUrl: '../shared/view/list.html'
changed to
templateUrl: 'list.html'
and it compiles fine now. Will leave this up incase anyone else has this issue.
Thanks to #Joel Joseph - Apparently the view needs to reside in the same directory as your parent component. I had the view .html file in a shared directory hence the problem.
templateUrl: '../shared/view/list.html'
changed to
templateUrl: 'list.html'
and it compiles fine now. Will leave this up incase anyone else has this issue.

How to debug angular-elements?

I built a project using angular-elements and managed to successfully embed a component into another application. What I would like to do now is be able to debug the original component from the application it is included in.
All the logic for the component is in one file, which is a concatenation of 4 files created by Angular during build - runtime.js, polyfills.js, scripts.js, main.js.
The js.map files for those 4 files are also created during build and I can successfully place & hit a breakpoint in the original main.ts file (after including the jsmaps in the directory with the output file for the element). However, I have been unable to find a way to debug the actual component.ts file from the application that is using it. The js.map for that component is also included in the bundle and I can view the component.ts file through Chrome DevTools, but if I put any breakpoints they will never be hit.
app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule, Injector } from '#angular/core';
import { createCustomElement } from '#angular/elements';
import { FormsModule } from "#angular/forms";
import { FirstWebElementComponent } from './first-web-element/first-web-element.component';
import { AppComponent } from './app.component';
import { HttpModule } from '#angular/http';
import { HttpClientModule } from '#angular/common/http';
import { ScenarioSelectorComponent } from './scenario-selector/scenario-selector.component';
#NgModule({
declarations: [
AppComponent,
ScenarioSelectorComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
HttpClientModule
],
providers: [],
entryComponents: [ScenarioSelectorComponent]
})
export class AppModule {
constructor(private injector: Injector) {}
ngDoBootstrap() {
const scenarioSelector = createCustomElement(ScenarioSelectorComponent, {injector: this.injector});
customElements.define('scenario-selector', scenarioSelector);
}
}
main.ts
import { enableProdMode } from '#angular/core';
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);
To the best of my understanding, the component.ts file logic is included in main.js file during build, but there doesn't seem to be a map created describing
the connection between the two.
For reference, here is the stuff I read / watched.
Building Custom Elements / Web Components with Angular 6
Angular Elements – A Practical Introduction To Web Components With Angular 6
Angular CLI doesn't support inline source maps anymore. Your best bet is to replace ng build with ngx build plus - https://github.com/manfredsteyer/ngx-build-plus
Then add a build plugin to replace the devtool with inline-source-map which will inline the sourcemaps into your bundle file enabling you to debug.
See: https://stackoverflow.com/a/54548171/1829251

Testing Material Design Angular components with jasmine

Edit2: Even more specific, using something like Material Button works fine. The Side Nav does not work well with the setup below, however.
Edit: I did more testing and found this is specifically related to Angular Material, as these errors don't occur without it. I'm still unsure how to fix it.
I'm trying to set up some basic tests for a new component, but I keep running into error after error. Specifically, after adding #angular/material to the project. The current error is:
Error: Found the synthetic listener #transform.start. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.
Which feels like a red herring to me.
Here is the spec:
import { async, ComponentFixture, TestBed } from '#angular/core/testing';
import { RouterTestingModule } from '#angular/router/testing';
import { MatSidenavModule } from '#angular/material/sidenav';
import { AngularNavigationComponent } from './angular-navigation.component';
describe('AngularNavigationComponent', () => {
let component: AngularNavigationComponent;
let fixture: ComponentFixture<AngularNavigationComponent>;
beforeEach(
async(() => {
TestBed.configureTestingModule({
declarations: [AngularNavigationComponent],
imports: [RouterTestingModule, MatSidenavModule]
}).compileComponents();
})
);
beforeEach(() => {
fixture = TestBed.createComponent(AngularNavigationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
And here is the component
import { Component, OnInit } from '#angular/core';
import { MatSidenavModule } from '#angular/material/sidenav';
import { RouterLink } from '#angular/router';
#Component({
selector: 'mysupercustomcat-navigation',
templateUrl: './angular-navigation.component.html',
styleUrls: ['./angular-navigation.component.scss']
})
export class AngularNavigationComponent implements OnInit {
constructor() {}
ngOnInit() {}
}
Can anyone tell me what I'm doing wrong, and also perhaps explain declarations vs. imports in the Testbed configuration area?
Edit: This is a hybrid app if that matters
I've added two key sections to avoid errors like this:
import { NO_ERRORS_SCHEMA } from '#angular/core';
is added at the top of the page and:
schemas: [NO_ERRORS_SCHEMA],
is added at the same level as declarations.
What does this do? This tells angular not to error on unknown elements or attributes. Now this works FOR THIS USE CASE because I am not super interested in integration testing. I believe that might cause problems in this case.
I am interested in unit testing, and ignoring template attributes is fine with me. Adding this lets me get to that level.
This answer is as complete as I could get it for the moment.

Angular4/5 dependency injection docs not working

https://angular.io/guide/architecture#services
I'm following the docs on angular.io to inject dependencies like services, etc. I did everything they said and when I try to run it, the console keeps telling me:
Uncaught ReferenceError: LedgerService is not defined
I am doing nothing crazy except creating a simple component with a service where both constructors have console.log commands (constructors in both the component and service). I've done everything Angular says to do in their 2 paragraphs that details this feature of Angular.
The component itself is being injected into the main app module (with the service being injected into the component) and both the component and service were created with the Angular CLI. So there isn't much I've even done at all minus trying to inject the service. So I'm not sure where it is going wrong but it is definitely not working and just shows a blank page (when it previously had basic content by default).
I created both units, tried to specify providers in both the app.module and the component.ts file and neither works and yields the same error--when Angular claims either could work. I've also specified it as a private service within the constructor of the component.ts file.
Everything I've seen relating to this is always for Angular 1 or 2. Neither of which are even remotely similar to Angular 4/5.
If you really want to see this code, fine but it's literally just framework and nothing else:
bookkeeper.component.ts:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-bookkeeper',
templateUrl: './bookkeeper.component.html',
styleUrls: ['./bookkeeper.component.css'],
providers: [LedgerServiceService]
})
export class BookkeeperComponent implements OnInit {
constructor(private service: LedgerServiceService) { }
ngOnInit() {
console.log("Ledger component works!");
}
}
app.module.ts:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { InterfaceComponent } from './interface/interface.component';
import { BookkeeperComponent } from './bookkeeper/bookkeeper.component';
#NgModule({
declarations: [
AppComponent,
InterfaceComponent,
BookkeeperComponent
],
imports: [
BrowserModule
],
providers: [
LedgerServiceService
],
bootstrap: [AppComponent]
})
export class AppModule { }
ledger-service.service.ts:
import { Injectable } from '#angular/core';
#Injectable()
export class LedgerServiceService {
constructor() {
console.log("wtf");
}
}
LedgerService is actually called LedgerServiceService because I initially created LedgerService manually and then tried to use the AngularCLI to generate a service and named it LedgerService and it created a service called LedgerServiceService. Naming is not what is wrong. I only initially called it simply LedgerService because I figured it would be confusing.
Your examples are missing the import.
Anywhere we use a custom type, we also need to import that type.
For that reason, in both the module and component you will need to add:
import { LedgerServiceService } from './your-path-here'
You can see this in the examples they give on https://angular.io/guide/dependency-injection

Categories