Saya memiliki aplikasi Angular 5 yang berfungsi tanpa masalah ketika saya menjalankannya dalam mode uji, yaitu ketika saya menjalankan aplikasi secara lokal menggunakan perintah ng serve
. Namun, ketika saya menerapkan aplikasi dalam mode produksi, yaitu melalui perintah ng build --prod
, aplikasi mengekspor tanpa masalah, tetapi ketika saya menggunakan aplikasi di lingkungan produktif, masalah ini muncul: (ini adalah gambar dari konsol browser dari google dan safari)
Konsol Google Chrome:
Konsol Safari:
Namun, jika sekarang saya mengekspor aplikasi menggunakan perintah berikut ng build --prod --aot false
, aplikasi akan berfungsi tanpa masalah.
Selanjutnya saya akan menunjukkan komponen yang terlibat dalam kesalahan yang dikomentari:
pengguna-online-quote.component.html
<app-navbar [loggedIn]=loggedIn></app-navbar>
<app-dynamic-form [answers$]="answers$"></app-dynamic-form>
pengguna-online-quote.component.ts
import { Component, OnInit } from '@angular/core';
import { DynamicFormService } from '../_services/dynamic-form.service';
import { RadioQuestion } from '../shared/_shared/answer-radio';
import { Observable } from "rxjs/Rx";
import { AuthService } from '../_services/auth.service';
import { Router, ActivatedRoute, Params } from '@angular/router';
@Component({
selector: 'app-user-online-quote',
templateUrl: './user-online-quote.component.html',
styleUrls: ['./user-online-quote.component.css'],
providers: [DynamicFormService, AuthService]
})
export class UserOnlineQuoteComponent implements OnInit {
totalPage:number;
actualPage:number;
percentageCompletion:number;
currentQuestion:string;
selectedOption:string;
imageSource:string;
loggedIn:boolean;
formId:string;
//public answers: any[];
//Signo $ porque es un observable
public answers$: Observable<any[]>;
constructor(private service: DynamicFormService, private authService: AuthService,
private activatedRoute: ActivatedRoute) {
}
ngOnInit() {
this.loggedIn=this.authService.isLoggedIn();
this.activatedRoute.queryParams.subscribe((params: Params) => {
this.formId=params['form'];
this.answers$=this.service.getAnswers(this.formId);
});
//this.answers=this.service.getAnswers("CAR00PR");
this.totalPage=4;
this.actualPage=1;
this.calculateAdvancePercentage();
this.currentQuestion="¿Pregunta de prueba?";
}
calculateAdvancePercentage(){
this.percentageCompletion=(this.actualPage/this.totalPage)*100;
}
next(){
this.actualPage=(this.actualPage+1);
this.calculateAdvancePercentage();
}
back(){
this.actualPage=(this.actualPage-1);
this.calculateAdvancePercentage();
}
}
bentuk-dinamis.component.html
<div class="space"></div>
<ngx-loading [show]="loading" [config]="{ backdropBorderRadius: '0px', fullScreenBackdrop:true }"></ngx-loading>
<div *ngIf="submitted===false" class="container">
<div class="row">
<div class="col-lg-2">
<div class="mx-2"></div>
</div>
<div class="col-lg-8">
<div>
<p>{{currentQuestion.description}}</p>
</div>
<div class="progress">
<div class="progress-bar" role="progressbar" [style.width]="percentageCompletion + '%'" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<hr>
<div>
<form [formGroup]="form">
<div *ngFor="let answer of answers$ | async">
<div [ngSwitch]="answer.controlType">
<div *ngSwitchCase="'radio'">
<div class="radios checkbox-group">
<div [hidden]="!(currentQuestion.id===answer.parent)" class="col-lg-12">
<input [formControlName]="answer.controlName" [id]="answer.id" type="radio" [value]="answer.label" (click)="next(null,answer.child)">
<label [for]="answer.id" class="button-label">
{{answer.label}}
</label>
</div>
</div>
</div>
<div *ngSwitchCase="'radio_textbox'">
<div class="radios checkbox-group">
<div [hidden]="!(currentQuestion.id===answer.parent)" class="col-lg-12">
<input [formControlName]="answer.controlName" [id]="answer.id" type="radio" (click)="showTextbox ? showTextbox = false : showTextbox = true;">
<label [for]="answer.id" class="button-label">
{{answer.label}}
</label>
</div>
</div>
<div [hidden]="!(currentQuestion.id===answer.parent)" class="input-group mb-3 col-lg-12">
<input [hidden]="!showTextbox" type="text" class="form-control" [placeholder]="answer.placeholder" [formControlName]="answer.controlName" [id]="answer.id">
<div class="input-group-append">
<button [hidden]="!showTextbox" class="btn btn-outline-secondary" type="button" (click)="next(null,answer.child)">Siguiente</button>
</div>
</div>
</div>
<div *ngSwitchCase="'file'">
<div [hidden]="!(currentQuestion.id===answer.parent)" class="col-lg-12">
<div class="form-group">
<label [for]="answer.id">{{answer.label}}</label>
<div class="custom-file">
<input [formControlName]="answer.controlName" type="file" class="custom-file-input" [id]="answer.id" lang="es" (change)="onFileChange($event)" #fileInput>
<label class="custom-file-label" for="customFileLang">{{fileName}}</label>
</div>
<div *ngIf="answer.required===true">
<small *ngIf="form.get(answer.controlName).status=='INVALID'" class="form-text text-muted-error">Debes tener una imagen de referencia para poder continuar</small>
</div>
</div>
<div class="my-4"></div>
</div>
</div>
<div *ngSwitchCase="'file_next'">
<div [hidden]="!(currentQuestion.id===answer.parent)" class="col-lg-12">
<div class="form-group">
<label [for]="answer.id">{{answer.label}}</label>
<div class="custom-file">
<input [formControlName]="answer.controlName" type="file" class="custom-file-input" [id]="answer.id" lang="es" (change)="onFileChange($event)" #fileInput>
<label class="custom-file-label" for="customFileLang">{{fileName}}</label>
</div>
<div *ngIf="answer.required===true">
<small *ngIf="form.get(answer.controlName).status=='INVALID'" class="form-text text-muted-error">Debes tener una imagen de referencia para poder continuar</small>
</div>
</div>
<div class="my-4"></div>
<div class="text-center">
<button
(click)='next(answer.validations,answer.next)'
class="btn btn-outline-secondary">
Siguiente
</button>
</div>
</div>
</div>
<div *ngSwitchCase="'textbox'" [hidden]="!(currentQuestion.id===answer.parent)" class="col-md-6 mb-3">
<label [for]="answer.id">{{answer.label}}</label>
<input [formControlName]="answer.controlName" type="text" class="form-control" [id]="answer.id" [placeholder]="answer.placeholder">
<div *ngIf="answer.required===true">
<small *ngIf="form.get(answer.controlName).status=='INVALID'" class="form-text text-muted-error">Este campo es obligatorio</small>
</div>
</div>
<div *ngSwitchCase="'textbox_next'" [hidden]="!(currentQuestion.id===answer.parent)">
<div class="col-md-6 mb-3">
<label [for]="answer.id">{{answer.label}}</label>
<input [formControlName]="answer.controlName" type="text" class="form-control" [id]="answer.id" [placeholder]="answer.placeholder">
<div *ngIf="answer.required===true">
<small *ngIf="form.get(answer.controlName).status=='INVALID'" class="form-text text-muted-error">Este campo es obligatorio</small>
</div>
</div>
<div class="my-4"></div>
<div class="text-center">
<button
(click)='next(answer.validations,answer.next)'
class="btn btn-outline-secondary">
Siguiente
</button>
</div>
</div>
<div *ngSwitchCase="'textarea'">
<div class="form-group col-lg-12" [hidden]="!(currentQuestion.id===answer.parent)">
<label for="description">{{answer.label}}</label>
<textarea [formControlName]="answer.controlName" class="form-control" id="description" rows="3"></textarea>
</div>
<div class="my-4"></div>
</div>
</div>
</div>
</form>
</div>
<div class="my-4"></div>
<div class="text-center">
<button
(click)='back()'
class="btn btn btn-outline-secondary">
Atrás
</button>
<button
[hidden]="currentQuestion.last==true"
(click)='cancel()'
class="btn btn btn-outline-secondary">
Cancelar
</button>
<button
[hidden]="currentQuestion.last==false"
[disabled]="form.invalid"
type="submit"
class="btn btn-outline-success"
(click)="onSubmit()">
Enviar Solicitud
</button>
</div>
</div>
<div class="col-lg-2">
<div class="mx-2"></div>
</div>
</div>
</div>
<div *ngIf="submitted==true" class="container">
<div class="space">
<div class="container">
<div class="row">
<div class="col-lg-1"></div>
<div class="col-lg-10 justify">
<p>Tu solicitud se ha enviado correctamente, debes esperar un máximo de 2 días para que el experto elabore una cotización
de acuerdo a tus requerimientos.
</p>
<div class="d-flex justify-content-center">
<a [routerLink]="['/dashboard_usuario/negociaciones/en_proceso']">Ver negociación</a>
</div>
</div>
<div class="col-lg-1"></div>
</div>
</div>
</div>
</div>
bentuk-dinamis.component.ts
import { Component, Input, OnInit, ChangeDetectorRef } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { AnswerBase } from '../shared/_shared/answer-base';
import { AnswerControlService } from '../_services/answer-control.service';
import { DynamicFormService } from '../_services/dynamic-form.service';
import { Question } from '../_models/question';
import { Observable } from "rxjs/Rx"
import { Router, ActivatedRoute, Params } from '@angular/router';
import { QuoteDto } from "../_dtos/quoteDto";
import { HttpClient, HttpResponse } from '@angular/common/http';
import {Location} from '@angular/common';
@Component({
selector: 'app-dynamic-form',
templateUrl: './dynamic-form.component.html',
styleUrls: ['./dynamic-form.component.css'],
providers: [ AnswerControlService ]
})
export class DynamicFormComponent implements OnInit {
@Input() answers$: Observable<AnswerBase<any>[]>;
form: FormGroup;
payLoad = '';
questionsList : Map<string, Question>;
totalPage:number;
actualPage:number;
percentageCompletion:number;
currentQuestion:Question;
previousQuestion:Question;
backwardQuestions:Array<string>;
loading:boolean;
fileName:string;
photo:File;
image:any;
nextDisable:boolean;
userId:string;
providerId:string;
formId:string;
submitted:boolean;
constructor(private qcs: AnswerControlService,
private dynamicFormervice: DynamicFormService,
private activatedRoute: ActivatedRoute,
private location:Location,
private router:Router) { }
ngOnInit() {
this.loading=true;
this.submitted=false;
this.fileName="Seleccionar un archivo";
this.nextDisable=true;
this.backwardQuestions= new Array();
this.currentQuestion=new Question('','',false);
this.form= new FormGroup({});
this.questionsList= new Map<string, Question>();
this.activatedRoute.queryParams.subscribe((params: Params) => {
this.userId=params['user'];
this.providerId=params['provider'];
this.formId=params['form'];
this.dynamicFormervice.getTotalPages(this.formId).subscribe(total => {
this.totalPage=total;
this.actualPage=1;
this.calculateAdvancePercentage();
this.dynamicFormervice.getQuestions(this.formId).subscribe(items =>{
items.map(item =>{
this.questionsList.set(item.id,item);
});
this.dynamicFormervice.getInitialQuestionId(this.formId).subscribe(id =>{
this.currentQuestion=this.questionsList.get(id);
this.previousQuestion=this.currentQuestion;
this.loading=false;
});
});
});
});
this.answers$.subscribe(a=>{
this.form = this.qcs.toFormGroup(a);
});
}
onSubmit() {
this.loading=true;
this.payLoad=JSON.stringify(this.form.value);
let quote:QuoteDto = new QuoteDto();
quote.requirements= this.payLoad;
this.dynamicFormervice.createQuote(quote,this.userId,this.providerId).subscribe((resp:HttpResponse<String>)=>{
this.dynamicFormervice.uploadQuotationImage(this.photo,resp.body.substring(resp.body.indexOf(':')+1,resp.body.lastIndexOf('"'))).
subscribe(resp => {
this.submitted=true;
this.loading=false;
});
});
}
calculateAdvancePercentage(){
this.percentageCompletion=(this.actualPage/this.totalPage)*100;
}
next(validatios:string, childId:string){
if(validatios!=null){
let controlRestrictions:string[]=validatios.split(',');
let validCount=0;
for (let cr of controlRestrictions) {
if(this.form.get(cr).status=='VALID'){
validCount++;
}
}
if(validCount==controlRestrictions.length){
this.nextDisable=false;
this.backwardQuestions.push(this.currentQuestion.id);
this.currentQuestion=this.questionsList.get(childId);
if(this.currentQuestion.last==true){
this.percentageCompletion=100;
}else{
this.actualPage=(this.actualPage+1);
this.calculateAdvancePercentage();
}
}
}else{
this.backwardQuestions.push(this.currentQuestion.id);
this.currentQuestion=this.questionsList.get(childId);
if(this.currentQuestion.last==true){
this.percentageCompletion=100;
}else{
this.actualPage=(this.actualPage+1);
this.calculateAdvancePercentage();
}
}
}
back(){
if(this.actualPage==1){
this.location.back();
}
else{
let questionId:string = this.backwardQuestions.pop();
this.currentQuestion=this.questionsList.get(questionId);
this.actualPage=(this.actualPage-1);
this.calculateAdvancePercentage();
}
}
cancel(){
this.navegateToProfessionForm();
}
navegateToProfessionForm(){
switch (this.formId) {
case 'ALB00PR':
this.router.navigate(['/expertos'], { queryParams: { profession: '1' } });
break;
case 'CAR00PR':
this.router.navigate(['/expertos'], { queryParams: { profession: '2' } });
break;
case 'DIS00PR':
this.router.navigate(['/expertos'], { queryParams: { profession: '3' } });
break;
case 'ELE00PR':
this.router.navigate(['/expertos'], { queryParams: { profession: '4' } });
break;
case 'CLI00PR':
this.router.navigate(['/expertos'], { queryParams: { profession: '5' } });
break;
case 'FUM00PR':
this.router.navigate(['/expertos'], { queryParams: { profession: '6' } });
break;
case 'MAQ00PR':
this.router.navigate(['/expertos'], { queryParams: { profession: '7' } });
break;
case 'PIN00PR':
this.router.navigate(['/expertos'], { queryParams: { profession: '8' } });
break;
case 'PLO00PR':
this.router.navigate(['/expertos'], { queryParams: { profession: '9' } });
break;
case 'JAR00PR':
this.router.navigate(['/expertos'], { queryParams: { profession: '10' } });
break;
case 'SOL00PR':
this.router.navigate(['/expertos'], { queryParams: { profession: '11' } });
break;
case 'TAP00PR':
this.router.navigate(['/expertos'], { queryParams: { profession: '12' } });
break;
default:
}
}
onFileChange(event) {
this.loading=true;
if(event.target.files && event.target.files.length > 0) {
let image:File = event.target.files[0];
let reader=new FileReader();
reader.readAsDataURL(image);
reader.onload = (event:any) => {
let base64=event.target.result
let filename=image.name;
let type=image.type;
this.reduceQuality(base64,filename,type,(file)=>{
this.photo = file;
this.fileName=this.photo.name;
this.loading=false;
});
}
}
else{
this.loading=false;
}
}
getBase64(file,callback) {
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function() {
let result = reader.result;
callback(result);
};
reader.onerror = function (error) {
console.log('Error: ', error);
};
}
reduceQuality(base64Image,filename,extension,callback){
let canvas = document.createElement('canvas');
let ctx=canvas.getContext("2d");
var image = new Image();
image.onload = ()=>{
var width = image.width,
height = image.height,
canvas = document.createElement('canvas'),
ctx = canvas.getContext("2d");
// set proper canvas dimensions before transform & export
canvas.width = width;
canvas.height = height;
// draw image
ctx.drawImage(image, 0, 0);
let url:string = '';
if(extension=='image/jpeg'){
url = canvas.toDataURL('image/jpeg', 0.1);
}
else{
url = canvas.toDataURL();
}
let file:File=this.dataURLtoFile(url,filename);
callback(file);
};
image.src = base64Image;
}
dataURLtoFile(dataurl, filename) {
let arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, {type:mime});
}
}
package.json
{
"name": "front-end",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build --prod",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "^5.2.0",
"@angular/common": "^5.2.0",
"@angular/compiler": "^5.2.0",
"@angular/core": "^5.2.0",
"@angular/forms": "^5.2.0",
"@angular/http": "^5.2.0",
"@angular/platform-browser": "^5.2.0",
"@angular/platform-browser-dynamic": "^5.2.0",
"@angular/router": "^5.2.0",
"angular2-text-mask": "^8.0.4",
"angularfire2": "^5.0.0-rc.6",
"bootstrap": "^4.1.0",
"core-js": "^2.4.1",
"firebase": "^4.12.1",
"jquery": "^3.3.1",
"moment": "^2.20.1",
"mydatepicker": "^2.6.3",
"ngx-loading": "^1.0.14",
"offcanvas-bootstrap": "^2.5.2",
"popper.js": "^1.14.3",
"rxjs": "^5.5.6",
"zone.js": "0.10.3"
},
"devDependencies": {
"@angular/cli": "1.6.5",
"@angular/compiler-cli": "^5.2.0",
"@angular/language-service": "^5.2.0",
"@types/jasmine": "~2.8.3",
"@types/jasminewd2": "~2.0.2",
"@types/node": "~6.0.60",
"codelyzer": "^4.0.1",
"jasmine-core": "~2.8.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~2.0.0",
"karma-chrome-launcher": "~2.2.0",
"karma-cli": "~1.0.1",
"karma-coverage-istanbul-reporter": "^1.2.1",
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.1.2",
"ts-node": "~4.1.0",
"tslint": "~5.9.1",
"typescript": "~2.5.3"
}
}
angular-cli.json
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"project": {
"name": "front-end"
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": [
"assets",
"favicon.ico"
],
"index": "index.html",
"main": "main.ts",
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "app",
"styles": [
"styles-app-loading.scss",
"styles.css",
"../node_modules/font-awesome/css/font-awesome.css"
],
"scripts": ["../node_modules/jquery/dist/jquery.slim.min.js",
"../node_modules/popper.js/dist/umd/popper.min.js",
"../node_modules/bootstrap/dist/js/bootstrap.min.js",
"../node_modules/offcanvas-bootstrap/dist/js/bootstrap.offcanvas.min.js"],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}
}
],
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"lint": [
{
"project": "src/tsconfig.app.json",
"exclude": "**/node_modules/**"
},
{
"project": "src/tsconfig.spec.json",
"exclude": "**/node_modules/**"
},
{
"project": "e2e/tsconfig.e2e.json",
"exclude": "**/node_modules/**"
}
],
"test": {
"karma": {
"config": "./karma.conf.js"
}
},
"defaults": {
"styleExt": "css",
"component": {}
}
}
Pertanyaannya mengapa aplikasi saya hanya berfungsi dengan baik ketika saya tidak menggunakan fitur AOT? Mengapa ini sangat aneh?
Apa yang harus saya lakukan untuk mengatasi masalah ini dan saya dapat menggunakan fitur AOT, karena saya tidak ingin aplikasi saya mendapat penalti kinerja? Ada ide?
Penting: Sebelum memisahkan aplikasi berdasarkan modul, aplikasi bekerja dengan baik dalam produksi. Masalah yang dijelaskan muncul setelah memisahkan aplikasi saya berdasarkan modul, namun komponen yang bermasalah ini adalah bagian dari modul utama.
angular.json
Anda dan apakah ada properti InputloggedIn
di komponen app-navbar? - person Gökhan Kurt   schedule 23.05.2020ng serve --aot
- person brandt.codes   schedule 28.05.2020