Bei mir reicht es die Datei zu löschen:
C:\Users\MY_USER\AppData\Roaming\JetBrains\PhpStorm2022.2\options\other.xml
Dann PhpStorm/Webstorm neustartne und es läuft wieder.
JavaScript Probleme,Tipps und Tricks
Bei mir reicht es die Datei zu löschen:
C:\Users\MY_USER\AppData\Roaming\JetBrains\PhpStorm2022.2\options\other.xml
Dann PhpStorm/Webstorm neustartne und es läuft wieder.
Die Change Detection von Angular wird immer ausgeführt bei einem Array Input, wenn sich die Referenz des Arrays ändert, aber nicht der Inhalt:
console.log([1] === [1]); // ergibt false
In Angular kann man die Change Detection beeinflussen, indem man die Strategie der Change Detection für eine Komponente ändert. Eine der Strategien ist die „OnPush“-Strategie, bei der die Change Detection nur dann ausgelöst wird, wenn sich die Eingangsparameter einer Komponente ändern oder wenn ein Ereignis aufgerufen wird.
Um sicherzustellen, dass die Change Detection nur ausgeführt wird, wenn das Input-Array geändert wurde, können Sie den OnPush-Strategie für die Komponente verwenden und eine Überwachungsfunktion für das Input-Array hinzufügen, die nur dann ausgelöst wird, wenn sich die Werte des Arrays ändern.
Hier ist ein Beispiel einer solchen Komponente:
import { Component, Input, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
@Component({
selector: 'app-example',
template: '...',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ExampleComponent {
@Input() items: any[] = [];
constructor(private cd: ChangeDetectorRef) { }
ngOnChanges(changes: any) {
if (changes.items && !this.arrayEquals(changes.items.previousValue, changes.items.currentValue)) {
this.cd.markForCheck();
}
}
private arrayEquals(a: any[], b: any[]): boolean {
return JSON.stringify(a) == JSON.stringify(a);
}
}
Somit wird die Komponente nur neu gerendert, wenn sich an dem Items Array wirklich etwas ändert und nicht nur die Referenz.
Um End-To-End-Tests mit Cypress und Angular zu schreiben, können Sie folgende Schritte ausführen:
npm install -D cypress installieren.npx cypress open im Hauptverzeichnis Ihres Projekts. Cypress öffnet eine Benutzeroberfläche, in der Sie Ihre Tests aufzeichnen und ausführen können.
describe('My First Test', () => {
it('Does not do much!', () => {
cy.visit('http://localhost:4200');
cy.contains('app-root h1', 'Welcome to my-app!');
});
});
cy.get(), cy.click() und cy.type().Um Cypress mit einem Docker-Container zu verwenden, können Sie folgende Schritte ausführen:
Dockerfile in Ihrem Projektverzeichnis mit den folgenden Inhalten:FROM cypress/browsers:node18.6.0-chrome105-ff104 # Install your application's dependencies COPY package.json yarn.lock ./ RUN yarn # Add your application code COPY . ./ # Run the tests CMD ["yarn", "cy:run"]
docker build -t my-app .docker run -it --rm -v $(pwd):/app my-app aus. Dies führt die Cypress-Tests innerhalb des Containers aus.Durch das Hinzufügen von -v $(pwd):/app werden Ihre Projektdateien in den Container gemountet und Cypress kann auf sie zugreifen.
Um einen Unit Test von einer Angular Komponente mit Abhängigkeiten (Dependencies) schreiben zu können, muss man die Abhängigkeiten unter Kontrolle bringen.
Wenn man dies nicht tut, schreibt man einen Integration-Test. Integration-Tests haben eine höhere Komplexität hat und gehen schneller kaputt.
Beipsiel einer Komponente „MyComponent“ mit einer Abhängikeit „MyService“:
export class MyComponent implements OnInit {
public serviceValue;
constructor(
private myService: MyService,
) {}
ngOnInit() {
this.serviceValue = this.myService.getValue();
}
}
Um in einem Jasmine Unit Test die Abhängigkeit von MyService zu kontrollieren, kann man einen Spy einsetzen, der an die die Stelle der Methode MyService::getValue gesetzt wird und die Sachen macht, die man für den Test gern hätte.
describe('MyComponent', () => {
let component: MyComponent;
let fixture: ComponentFixture<MyComponent>;
let myService:MyService;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [MyComponent,],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(MyComponent);
component = fixture.componentInstance;
myService = TestBed.inject(MyService);
});
it('spy should set value', () => {
spyOn(myService,'getValue').and.returnValue('foo');
fixture.detectChanges();
expect(component.serviceValue).toBe('foo');
});
});
In dem Beispiel wird die Methode getValue der Klasse MyService mit einem Spy überschrieben und dem Spy mitgeteilt, dass er den Wert ‚foo‘ zurückgeben soll.
JavaScript ist keine funktionale Programmiersprache, aber die wichtigsten Prinzipien der funktionalen Programmierung lassen sich trotzdem beim Programmieren an einigen Stellen anwenden.
Diese Prinzipien sind u.a.:
An den folgende Beispielen und sehr praktischen Array Methoden soll der Unterschied zwischen funktionaler und nicht funktionaler Programmierung gezeigt werden:
Die Array methode forEach ermöglicht es funktional über ein Array zu iterieren, ohne eine sich verändernde Variable i zu verwenden.
// Beispiel alle Einträge in companies auf der Konsole ausgeben
//nicht funktional
for(let i = 0; i < companies.length; i++) {
console.log(companies[i]);
}
//funktional
companies.forEach(function(company) {
console.log(company);
});
Die Array Methode filter entfernt Einträge aus einem Array, die nicht der übergebenen Bedingung entsprechen und gibt diese zurück. Man beachte, dass das ursprüngliche Array nicht verändert wird und die filter Mezhode selbst ein Funktion höherer Ordnung ist, weil als Parameter eine Funktion übergeben wird.
Um Selenium Tests in Firefox und Chrome im Headless Modus auszuführen mit Protractor, kann man folgende Konfiguraton verwenden in der protractor.conf:
exports.config = {
....
multiCapabilities: [
{
browserName: 'chrome',
chromeOptions: {
'args': ['--headless']
},
},
{
browserName: 'firefox',
firefoxOptions: {
args: ['--headless']
},
'moz:firefoxOptions': {
args: ['--headless']
}
},
],
...
};
Um eine Kompatibilität mit alten Browsern, wie dem Firefox Version <= 5 zu erreichen, kann man das angular http Modul nicht verwenden. Das ngx-translate Module bneötigt einen Loader, der die richtige Sprache lädt per Ajax Request. Dies läst sich auch mit dem XMLHttpRequest und einem Observalbe lösen:
import {Injectable} from '@angular/core';
import {TranslateLoader} from '@ngx-translate/core';
import {Observable} from 'rxjs/Observable';
@Injectable()
export class LanguageLoader implements TranslateLoader {
getTranslation(lang: string): Observable<any> {
return Observable.create(function (observer) {
let url = `./assets/i18n/${lang}.json?=` + new Date().getTime();
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == XMLHttpRequest.DONE || xhr.readyState == 4) {
let response = JSON.parse(xhr.responseText);
observer.next(response);
observer.complete();
}
}
xhr.open('GET', url, true);
xhr.send(null);
});
}
}
In der app.module.ts kann man dann den Loader wie folgt einbinden:
TranslateModule.forRoot({
loader: {provide: TranslateLoader, useClass: LanguageLoader}
})
Bei einem Fehlgeschlagenen Request kann man sehr komfortabel nochmals anfragen mit der Methode retry():
import 'rxjs/add/operator/retry'; ... const result = this.http.get(url) .retry(2);
Die neue Javascript Methode console.table() ist sehr hilfgreich, um Objekte und Arrays auf der Konsole darzustellen.
Beispiel:
var data = [
{"id": "Open"},
{"id": "OpenNew", "label": "Open New"},
null,
{"id": "ZoomIn", "label": "Zoom In"},
{"id": "ZoomOut", "label": "Zoom Out"},
{"id": "OriginalView", "label": "Original View"},
null,
{"id": "Quality"},
{"id": "Pause"},
{"id": "Mute"},
null,
{"id": "Find", "label": "Find..."},
{"id": "FindAgain", "label": "Find Again"},
{"id": "Copy"},
{"id": "CopyAgain", "label": "Copy Again"},
{"id": "CopySVG", "label": "Copy SVG"},
{"id": "ViewSVG", "label": "View SVG"},
{"id": "ViewSource", "label": "View Source"},
{"id": "SaveAs", "label": "Save As"},
null,
{"id": "Help"},
{"id": "About", "label": "About Adobe CVG Viewer..."}
];
console.table(data);
Erzeugt im Chrome die folgende Ausgabe in den Developer Tools:
Bei einer Angular Anwendung muss man standardmäßig die index.html aufrufen, damit die Anwendung startet auf einem Apache Webserver. Damit dies auch ohne /index.html nur mit der Domain allein (www.foo.de) funktioneirt, muss man folgendes einstellen:
1. Erstellen einer .htaccess Datei in src/.htaccess mit dem Inhalt:
DirectoryIndex index.html
2. Ändern der Base Url in der src/index.html
<base href="">
3. ggf. hinzufügen der .htaccess zum Build Prozess in der .angular-cli.json
"apps": [
{
"assets": [
"assets",
"favicon.ico",
".htaccess"
],