Benutzer abhängige Ansichten oder Aktionen sind in der Shopware 6 Administration sehr selten. Aber gerade auf dem Dashboard kann toll Ansichten und Nachrichten unterbringen, die speziell für einen Benutzer oder eine Benutzergruppe gedacht sind. Aber dafür muss man wissen wer gerade eingeloggt ist, um z.B. ein Criteria mit den richtigen Filtern zu versehen.
die Art und Weise erinnert mich etwas wie ich damals bei meinen cJSv2-Framework die Controller an Elemente gebunden und initialisiert habe.. der default-Name der Init-Methode war da auch init.
Der DomAccess-Helper ist super und sollte man so verwenden. Über den kann man auch den QuerySelector nutzen und dass schützt hoffentlich davor, dass ein Haufen klassischer Webdesigner versuchen JQuery wieder da rein zu bringen. Der HttpClient ist auch nett aber man kann genau so gut direkt mit fetch() arbeiten, wenn man nicht unbedingt irgendwelche Steinzeit Browser supporten möchte. Aber besonder mag ich von den Helpern DeviceDetection.isTouchDevice() weil man damit einfach unterschieden kann ob man gerade ein Touch oder ein MouseEnter
Event nutzen muss.
Wenn man in der Storefront an einem eignem JavaScript-Plugin arbeitet ist es beim Debuggen, oft nervig, dass der JavaScript Code nicht direkt lesbar ist. Oft weiß man beim eigenen Code direkt was los ist, aber gerade wenn 3rd Party Plugins auch mit rein spielen, kommt man nicht drum herum sich Exceptions mit lesbaren Stacktrace anzeigen zu lassen.
Das ist zum Glück extrem einfach:
* Port 9998 aus dem Docker-Container durchleiten
* Dem SalesChannel in dem man entwickelt die Domain "localhost" zu ordnen
* das Script bin/watch-storefront.sh starten
Nun kann man localhost:9998 im Browser aufrufen. Der JavaScript Code ist lesbar und Änderungen werden sofort übernommen ohne dass man die Storefront neu bauen muss.
Es gibt viele Code-Styling Presets die man einfach in PHPStorm einstellen kann, wie PSR-2 für PHP. Für JavaScript gibt es da wenige und z.B. Prettier wird auch erstmal via NPM installiert.
Dann kann das Problem kommen, dass man Node nicht unter Windows laufen lässt sondern in WSL. Aber da hat PHPStorm zum Glück eine eine fertige Framework-Integration für.
Damit kann Prettier auch für die normale Reformatierung von PHPStorm mit JS-Dateien ausgewählt werden.
Manchmal muss man auch heute noch prüfen ob der Benutzer JavaScript
auf der Seite erlaubt hat oder ob ein Framework wie JQuery korrekt geladen und nicht geblockt wurde.
Prinzip ist einfach. Man versucht die Meldung mit JavaScript nach dem Laden der Seite auszublenden. Wenn es nicht klappt, liegt ein Problem vor und die Meldung ist für den Benutzer sichtbar.
Hier wird erklärt wie man im Chrome bewußt JavaScript deaktiviert, damit man solche Fälle testen kann.
Ich hab cJSv2 jetzt soweit erweitert, dass man nun sich einfach in verschiedene Services in seine Controller injecten lassen kann (und ist dann unter seinem Namen oder einem Alias dort direkt aufrufbar). Jeder Service ist Singleton, so dass jeder Controller auf die selbe Instance des Services zugreift.
An sich wird damit die cjsGetController Methode, mit der sich Controller untereinander mit ihren Namen konnten, überflüssig und man kann einfach asynchrone/reactive Lösungen basteln.
Hier erst einmal ein kleines synchrones Event-System:
Das direkte Einbinden als Base64 Data-URL ist echt praktisch, aber man will ja nicht, dass die Benutzer nun endlos riesige Bilder darüber einbinden. Deswegen ist es eine gute Idee, die Bilder beim Einfügen auch gleich zu verkleinern. Das ist zum Glück mit dem Canvas-Element sehr einfach.
Die Callback-Function:
let onImageUploadFunc = function (elementId) {
return function(image) {
resizeImage(image[0], elementId);
}
};
function resizeImage(file, elementId) {
let image = new Image();
let url = window.URL ? window.URL : window.webkitURL;
image.src = url.createObjectURL(file);
image.onload = function (e) {
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
let width = 600;
let factor = image.width / width;
let height = image.height / factor;
Eine Admin-UI lebt nicht nur von Tables sondern auch von sehr vielen Forms. Die möchte man ja nur ungern komplett per Hand bauen sondern etwas wie JSON-Schema benutzen, da man das auch auf Server-Seite für die Validierung nutzen kann.
Schon als ich mit React arbeiten musste, war ich sehr von den vorgefertigten Admin-Templates angetan. Jetzt darf ich auch mal damit rumspielen und meine ersten Erfahrungen damit sind schon relativ positiv. Da ich mit meinem Job synchron bleiben wollte habe ich mit CoreUI angefangen.
Die Installation über GitHub ist einfach und schnell.
Um ein eigens View anzulegen muss man an sich drei Dinge tun.
1. Die View anlegen:
2. In router/index.js die Component importieren und in die Router-Config einfügen:
3. In containers/_nav.js einen Link für die Sidebar einfügen:
Frameworks gelten ganz ganz oft als etwas sehr kompliziertes und mächtiges Werkzeug, das nur von wenigen auserwählten entwickelt und designed wird. Wenn ein Framework etwas nicht kann wird es meistens so hingenommen und darauf gehofft, dass es vielleicht doch noch irgendwann mal eingebaut wird. Meistens würde man sich nie trauen, sich dabei einzubringen oder einzumischen.
Man selbst ist ja einfacher "Anwender" und wie die eigenen Anwender, die das eigene Programm nutzen, das wieder das Framework nutzt, sollte man sich nicht die Dinge einmischen, von denen man keine Ahnung hat.
Ich habe über die Jahre doch ein paar Frameworks gebaut. Gute, schlechte, noch schlechtere und auch welche, die durch die allgemeine Frameworks ersetzt wurden. Auch mal ein Bugfix für ein vorhandenes Framework war dabei.
Wichtig ist dabei, dass man sich klar wird, dass Frameworks im Kern meistens alles andere als hoch komplex sind. Das würde schon dem
Zweck des Frameworks widersprechen, das ja für möglichst viele Anwendungszwecke funktionieren soll. Der Core ist meistens sehr einfach und klar strukturiert. Komplexität kommt meistens über Zusatzfunkionen rein, die wieder rum nur die Kernfunktionen bedienen. Wenn diese Kernfunktionen gemischt werden und kann es am Anfang sehr unübersichtlich erscheinen, weil teilweise nicht ganz klar ist, was wofür da ist.
Bei React mit Hooks kann selbst das Mischen von useState und useEffect teilweise kompliziert sein, weil aus der Sicht des Entwicklers vielleicht, von diesen Funktionen was anderes Erwartet wird, als im Framework-Kern damit wirklich erreicht wird.
Frameworks machen keine Zauberrei aber dafür sehr viel Referenz-Verwaltung. Meiner Erfahrung nach beschäftigt man sich im Framework-Kern zu 75% allein damit Instanzen und Referenzen zu erzeugen und zu verwalten.
Um das ganze etwas zu verdeutlichen habe ich mich einmal hingesetzt und in unter einer Stunde (hatte ich mir auch so vorgegeben) ein kleines Framework gebaut, das useState und useEffect reimplementiert und zeigt, wie man das Verhalten dieser Funktionen nutzt, aber auch, welche Funktion für das Framework wirklich dahinter steckt. Weil am Ende kommt man zu meist immer zu selben Strukturen, die bei allen Frameworks immer nur etwas anders benannt und implementiert sind.
Ich vertrete ja die Meinung, dass React erst mit der Einführung der Hooks wirklich nutzbar wurde. Vorher war alles zu aufwendig beim Prüfen des States und dem beachten der Lifecycles. Durch useState und useEffect geht jetzt alles einfacher und schneller. Wer sich schon immer gefragt hat, wo der Unterschied in useState und useReducer liegt, wird sicher diesen Artikel Under the hood of React’s hooks system sehr interessant finden und lernen, das useState einfach nur ein anderes Interface für useReducer ist.
Ich habe mir diesen Artikel durch gelesen, warum man bis 2020 Python lernen sollte. Aber irgendwie überzeugen mich diese Gründe so gar nicht. Ich hab schon mal ein paar Dinge mit Python gemacht und am Ende, war es eine Sprache wie jede andere. Viel weniger Boilerplate-Code als Java, aber dass ist keine Kunst und mit Lombok und ähnlichen hat sich auch bei Java viel getan. Aber mal der Reihe nach:
1. Automatisiert triviale Aufgaben Das kann ich mit PHP (mit Symfony-CLI) auch ganz gut. Kleine Tools schreiben ohne viel Framework wie JRE + Spring + JPA + etc haben zu müssen. Aber sobald der Code Compiler wird, kommt auch da alles hinzu. Ich sehe da eher den Vorteil dass Python auf IoT-Geräten gut läuft und man sehr viel Overhead einsparen kann.
2. Schneller Einstieg und einfache Syntax Stimmt. Das Beispiel ist zwar nicht aussagekräftig da der Boilerplate-Code mit zunehmenden Code immer geringere Anteile einnimmt und man sich viel Code heute ja auch automatisch generieren lassen kann. IDEs sei dank bringt einen diesen Code zu schreiben kaum einen zeitlichen Nachteil. Also... ja.. Python ist nicht schwer, aber auch nicht leichter als PHP oder JavaScript. Java ist an sich auch nicht schwer, man muss nur eben Classes und Packages richtig nutzen und schon ist alles sehr übersichtlich. Je weniger Struktur man braucht desto schwieriger wird es auch für die IDE bei der Codevervollständigung zu helfen. Java ist da einfach immer noch weit vorne.
3. Data Science Geil... wenn ich Python kann, kann ich Data Science? Nein. Irgendwer hat man angefangen Python in dem Bereich zu nutzen und hat gute Libs geschrieben. Oft sind die Libs Ausschlag gebender als die Sprache an sich. Also war es wohl eher Zufall dass in dem Bereich Python hauptsächlich eingesetzt wird und nicht der Sprache an sich geschuldet. Bloss weil ich das Hauptwerkzeug für einen Berufszweig benutzen kann, kann ich auch den Beruf ausüben... ich kann mit einem Skalpell scheiden!!!!
4. Machine Learning Ja.. auch cool. Tolles und komplexes Thema. Werkzeuge dafür zu erlernen ist hier sicher nicht die größte Herausforderung in dem Bereich.
5. Ressourcen Wie oben schon beschrieben. Wenn die Lib mein Problem löst, nehme ich die Sprache für die es die Lib gibt. Da ist es egal ob es Python, Java oder C++ ist. Ich nehme einfach das, was mein Problem schnell und einfach löst. Also bringt es mir nichts Python zu lernen, weil es tolle Libs gibt. Wenn ich eine Lib benutzen will, dann habe ich ein Grund mir die Sprache anzueignen.. vorher nicht (außer aus Spass oder Lerndrang).
6. Community Das gilt an sich für jede größere Programmiersprache. Stackoverflow hilft, deutsche Foren liefern nie eine Lösung. Alles wie immer.
Zusammenfassend kann ich für mich nur sagen. Es lohnt sich für mich nicht eine neue Sprache zu lernen, weil man theoretisch super tolle Dinge damit machen könnte, die ich entweder nicht beherrsche oder nicht benötige. Die Standardaufgaben können alle Sprachen fast gleich gut und da zwischen den Sprachen zu wechseln fällt auch entsprechend leicht. Mal mit einer Sprache rumspielen ist immer lustig und macht Spass, aber eine Sprache wirklich lernen ist nru nötig wenn man es benötigt. IoT-Geräte sehe ich da noch als den wahrscheinlichsten Grund, warum ich mal wieder was mit Python machen sollte.
Manchmal braucht man schnell und einfach einen HTTPS-Server um z.B. eine App auszuliefern, die auf die Kamera des PC oder Smartphones per WebRTC zugreift. Das geht an sich ganz einfach wenn man weiß, was man alles braucht.
Damit hat man direkt einen HTTPS-Server bei dem man nur noch das unsichere Zertifikat akzeptieren muss.
Wenn man Windows verwendet muss man über die Bash (WSL) OpenSSL, NodeJS und NPM installieren und dann ist es wie unter Linux.. man befindet sich dann ja auch in einem Linux....
Jeder kennt es sicher. Man baut eine Webanwendung, mit ein wenig HTML5, ein wenig JavaScript und was sonst so an CSS und SVG dazugehört. Firefox ist glücklich, Chrome natürlich auch und sogar Safari beschwert sich nicht. Man hat alles geschafft und und will in den Feierabend gehen. Die Sonne lacht, die Laune ist gut und draußen brüllen die Vögel. Man will gerade den PC in den Energiesparmodus versetzen und aufstehen da zieht eine leichte kühle Brise auf. Der Himmel wird dunkel und der Atmen kondensiert direkt vor einem.. Gänsehaut und alle Haare stellen sich auf. Der Geruch von Tod und Verwesung steigen einen in die Nase. Raben krächzen aufgeregt von ihren Plätzen (es ist immer ein Fehler sich ein Büro mit Raben zu teilen....). Das ungute Gefühl übernimmt die Oberhand. Das Ticket des Grauens ploppt auf. Schon der Titel verrät, dass der schlimmste anzunehmende Unfall geschehen ist. Es kommt von der typischen Art von Mitarbeitern, die aus versehen mal einen Dämon beschwören oder das Tor zur Hölle öffnen. Diesmal ist es nur ein Zombie. Gut nicht einfach ein Zombie. Es ist wieder der Zombie, der jedes mal auftaucht in solchen Situationen. Nervig, man mag ihn auch nicht einfach weg schicken. Es ist die Art von Zombie, die in dein Haus eindringen wollen und, obwohl du schon alle Türen offen gelassen hast, immer nur gegen die Außenwand rennt. Um dein Haus hat sich schon eine Traube anderer Zombies gebildet, die dem einen dummen Zombie nur ungläubig dabei zu gucken, wie er immer und immer wieder gegen die Wand rennt.
"Mit dem Internet Explorer geht das nicht...". Du versuchst am Verwesungsgeruch fest zustellen, ob es der IE11 ist oder der Mitarbeiter eine noch ältere Version ausgebuddelt hat. Es ist nur der IE11, aber trotzdem würde ein Surströmming-Deo seinen Geruch schon ungemein verbessern.
Es bleibt nur eins übrig: Den Zombie verscheuchen, dem Mitarbeiter mitteilen, dass man sich morgen gleich als Erstes darum kümmern wird und sich einreden, dass Menschen die noch einen Internet Explorer benutzen es auch verdient haben in Probleme zu laufen.
Durch die Transition-Tag wird das Element eingeschlossen, dessen Änderung mit der Animation verknüpft werden soll. Der Name ist der der erste Teil des Animationsnamens.
.dialogbox-enter-active {
animation: open 0.8s;
}
.dialogbox-leave-active {
animation: open 0.4s reverse;
}
AngularJS hat beim IE (älter als Edge) ein Problem mit ng-change, wenn ein Input über eine DataList gefüllt wird. Dann wird einfach kein Event ausgelöst. Mit einer kleinen Hilf-Function und $scope.$applyAsync() in der Scope-Function kann man das aber reimplementieren.
function onChangeIE(value){
var ua = window.navigator.userAgent;
if((ua.indexOf('Trident/') > 0 || ua.indexOf('MSIE ') > 0) && ua.indexOf('Edge/') <= 0) {
angular.element(document.getElementById('my-ng-controller-element')).scope().myInputModel = value;
angular.element(document.getElementById('my-ng-controller-element')).scope().myNgChangeFunction();
Die beste Lösung wäre solche alten Browser nicht mehr zu supporten und dann vielleicht auch auf Vue.js oder eine aktuelle Angular-Version zu wechseln.
Aber für schnelles Prototypen, wo man wenig Code schreiben will, ist AngularJS noch immer sehr gut. Teilweise ist man so schnell damit, dass man während einer Diskussion die Ideen direkt nebenbei umsetzen und ausprobieren kann. Wenn man erst einmal viele Components schreiben muss, geht es nicht so gut, wie mit den AngularJS Templates und Dingen wie ng-options. Mit Vue.js ist man mit etwas Übung aber auch ähnlich schnell.
Eine Art von Queue, wo viele Items drin abgelegt werden können, aber erst wenn alle Items valide sind, alle auf einmal verarbeitet werden. Es werden Proxies benutzt, um auf Änderungen an den Items reagieren zu können. Ein hinzu gefügtes Item kann also an eine async Function weiter gereicht werden und wenn dort das Item geändert wird, wird direkt wieder versucht die Queue zu flushen.
Man muss drei Functions mit geben: Validator zum prüfen der einzelnen Items, Cosumer zum Verarbeiten der einzelnen Items und onEmpty, die ausgeführt wird, wenn der Flush durch ist.
let flushQueue = {
items: [],
getChangeHandler: function(service){
return {
set: (obj, prop, newval) => {
obj[prop] = newval;
service.consume(false);
}
}
},
consumer: null, //user function
onEmpty: null, //user function
validator: null, //user function
validate: function() {
let result = true;
this.items.forEach((item) => {
if(!this.validator(item)) {
console.log(item);
result = false;
}
});
return result && this.items.length > 0;
},
consume: function(tested) {
if(tested || this.validate()) {
var item = this.items.shift();
if(this.consumer){
try{
this.consumer(item);
}
catch(e){
}
}
if(this.items.length > 0) {
this.consume(true);
}
else if(item && this.onEmpty) {
this.onEmpty();
}
}
},
add: function(itemIn) {
let item = new Proxy(itemIn, this.getChangeHandler(this));
this.items.push(item);
this.consume(false);
return item;
},
addAll: function(items) {
let out = [];
items.forEach((itemIn, key) => {
let item = new Proxy(itemIn, this.getChangeHandler(this));
this.items.push(item);
out[key] = item;
});
this.consume(false);
return out;
}
};
Wenn man JSON-Dateien mit längeren Texten bearbeitet, ist dieses oft sehr unübersichtlich, weil JSON keine Zeilenumbrüche innerhalb eines String zulässt. Zum Glück können einen IDEs da helfen, da sie eine Zeile in mehreren Zeilen im Editor darstellen können.
Wenn man sich generische Componenten in React oder Vue bastelt, wie Lists oder Grids/Tables kommt man schnell zu dem Punkt, wo man Werte aus einem Object extrahieren muss. Z. B. wenn man sich in einer Table eine Column definiert. Man könnte eine function rein reichen, die auf die konkrete Implementierung des Item zugeschnitten ist, aber oft will man nur die vorhandenen Werte im Object zur Anzeige bringen und nicht zu viel schreiben.
Wenn man einen Key hat und auf der ersten/obersten Ebene agiert wie bei item.id ist alles einfach. Bei item.sub.moreSub.verySub.id ist es schon schwieriger.. naja eigentlich nicht und jeder hat so etwas schon mal gebastelt. Hier meine Lösung die vielleicht jemanden 5 Minuten Arbeit ersparen kann :-)
function getObjectValue(obj, path){
let curObj = obj;
const parts = path.split(".");
for(let i = 0; i < parts.length; i++){
if(curOjb[parts] !== undefinded){
curObj = curObj[parts];
}
else {
return undefined;
}
}
return curObj;
}
Manchmal hat man bei React trotz besserem Wissens sich Strukturen gebaut, die es schwierig machen, den Datenfluss sauber abzubilden. So passierte es plötzlich, dass in einer Child-Component etwas geändert wurde und diese Änderung es verlangte, dass in einer Geschwister Child-Component eine Liste neu geladen werden sollte. Diese Component lud die Liste von einer REST-API selber und bekam die Liste nicht von der Parent-Component. Doof. Per Callback wurde die Parent-Component von der Änderung unterrichtet, aber diese konnte das Neuladen ja nicht so einfach anstoßen, weil es an sich keine State-Änderung gab.
Man braucht ein Flag, dass sich ändert, wenn ein Refresh der Child-Component nötig wurde. Da reicht ein bool-Flag, das bei jeder Änderung seinen Zustand ändert.
Damit child2 nun was laden kann muss man nicht mehr groß selbst prev-props mit next-props vergleichen sondern kann useEffect() verwenden:
useEffect(() => {reloadList()}, props.refresh);
Schön einfach und kompakt. Das man mit useEffect() direkt auf einzelne props/Änderungen reagieren kann, macht mir React schon sehr viel sympathischer. Erinnert mich an Watcher und Proxies aus Vue, nur sehr viel einfacher zu verwenden.
Ich hatte in den letzten Tagen etwas mehr mit verschiedenen Formular-Generatoren in verschiedenen JS-Frameworks zu tun. Vorraussetzung bei allen was, dass die JSON-Schema als Schema-Sprache unterstützten. Bis jetzt war keiner dabei der wirklich fehlerlos funktionierte. Ich kann jetzt nicht sagen, ob es nicht doch irgendwie an mir lag, aber falls jemand bestätigen kann, das ein Problem kein generelles Problem dabei ist, wäre ich doch sehr glücklich und würde mich noch mal genauer damit beschäftigen.
Vue: FormSchema Native: lief erstmal ganz gut, aber wenn sich das Schema oder das Model im State geändert hat, würde die Form nicht neu gerendert. Wenn man eine Form-Component schreibt in die verschiedene Schemas rein gericht werden können zur Laufzeit ist das echt doof. Ansonsten machte es nämlich einen guten Eindruck.
React: react-jsonschema-form: bis jetzt das Beste nur gibt es leichte Probleme wenn man $schema mit etwas anderen als dem default-Schema rein reicht. Aber ansonsten funktioniert bis jetzt am Besten. Auch mit 3 Forms auf der Seite.
AngularJS Angular Schema Form: Wenn man nur eine Form auf der Seite braucht funktioniert es perfekt. Wenn ich aber zwei Forms mit zwei unterschiedlichen Schemas verwende, wollte die zweite Form nicht mehr rendern. Aber eine Form allein funktionierte echt super. Leider ist AngularJS aber ja nicht mehr wirklich supported und ich hätte lieber etwas für Vue gehabt, was genau so gut funktioniert.. eben dann auch mit 2-3 Form pro Seite. Edit: Problem hat sich in Luft aufgeloest...
Meine Suche geht weiter, weil ich Vue doch lieber mag als React. Oder am Ende doch selber schreiben oder ein andere auf JSON-Schema anpassen?
Nach dem Ich mich etwas mit Redux beschäftigt habe, habe ich mir mal einen eher aktuellen Spiele-Prototypen von mir vorgenommen und geguckt, ob man diesen auf ein ähnliches Konzept umbauen kann. Also dass alles per Actions gesteuert wird. Alles was man macht wird per Action rein gereicht, in einer Loop(Interval) von einem Handler verarbeitet und dann gerendert, wenn mindestens eine Action ausgeführt wurde.
Nach einer schnellen Betrachtung wurde aber klar, dass ich da nicht viel umbauen konnte, weil die Engine schon rein der Logik wegen so implementiert wurde. Ich hab es einfach so schon gemacht ohne groß drüber nachzudenken. Ich hatte zusätzlich noch Action-Groups eingeführt, die dafür sorgen, dass immer nur die erste Action einer Gruppe ausgeführt wird (um Actors sich über die Map bewegen zu lassen, wobei alle Schritte vorberechnet sind und nicht vor dem Schritt dieser erst berechnet werden muss). Es gibt zwei Lanes: fast und slow. "slow" für das Bewegen von Actors auf der Map und "fast" für Eingaben und Dinge die an sich in Echtzeit da sein müssen. Ein kleine Verzögerung ist aber ok.
addIntervalEvent: function(eventType, eventArgs, group, lane){
this.interval.queue.push({lane: lane ? lane : 'slow',
type: eventType, args: eventArgs, parent: this.interval,
group: group});
},
performIntervallTick: function(lane){
//filter to perform events of a lane and remove this performed events
let filterCheck = [];
let render = false;
let newQueue = this.interval.queue.filter(item => {
let res = true;
if(item.lane == lane){
if(this.eventHandling[item.type] && (item.group === null || !filterCheck[item.group])){
this.eventHandling[item.type](item.args, item.parent, this);
filterCheck[item.group] = item.group;
res = false; //was performed and is removed from the queue
render = true;
}
}
return res;
});
this.interval.queue = newQueue;
//using the same method to trigger field-events
if(render){
this.globalKeyListener({keyCode: 0}, true);
this.renderViewport();
}
},
Hier bei ist der Controller der State und wird durch die Actions verändert. Eine Action wird mit einer Veränderung des State gleichgesetzt, da einmal oder zwei Rendern ohne das es nötig gewesen wäre in der Gesamtheit nichts ausmacht.
Was ich dabei gelernt habe ist, dass es schwer ist in JavaScript anders zu arbeiten, wenn man die Verarbeitung und die Ausgabe von einander entkoppelt, was gerade bei Anwendungen mit Grafik schwer ist nicht zu tun.
Heute saß ich vor der Dokumentation zu den neuen Hooks bei React und las mit durch welche Probleme die alle lösen sollen. Indirekt wurde gesagt, dass sie Redux unnötig machen sollen.. also war für mich die Zeit gekommen mir wirklich mal Redux anzusehen. Erstmal zu verstehen, was es tut, ist nicht ganz so einfach, wenn man sich deren Doku durchliest. Was gefühlt aber nur an deren Doku liegt, die viel zu zerstückelt ist, um einen schnellen Überblick zu bekommen.
Ich habe mit Hilfe von anderen Seiten dann heraus bekommen. Dass Redux einen State pro Reducer hält und der alle Actions bekommt und dann mit eigener Logik, die für ihn interessanten Actions ab arbeitet. Alter State geht rein und neuer geht raus. Eine Action hat einen Typ und ein Payload. Wenn sich der State ändert, wird etwas getriggert. Aber ich fand, dass doch für einfache Beispiele zu viel Code da war um es zu verstehen.
Um also das Prinzip von Redux zu verstehen habe ich dann mal 20min investiert und mir ein ähnliches Kontrukt geschaffen. Etwas Topic orientierter mit den States, so dass man die Reducer pro Action hat, aber vom Prinzip ist es alles relativ einfach und das Bootstrapping wurde daruch auch übersichtlicher.
Die meisten Beispiele zu Redux bestehen sowie so zu 50% aus React. Aber ich wollte ja Redux verstehen und nicht Redux+React (ja.. die gibt es wirklich auf getrennt von einander!)
Lief erstaunlicher Weise direkt wie es sollte (nach dem ein kleiner Fehler bei einer falschen Variablen behoben war).
Damit sollte man durch aus das gesamte Statemanagement einer Componente abbilden können. Wenn man nun noch Events verwenden würde, geht es schon stark in Richtung Reactive-Programming.
Bei Vue.js werden bei den Props, die an eine Unterkomponente übergeben werden, diese als Referenz übergeben. Wenn ich in der Unterkomponente etwas Ändere, werden diese Änderungen im selben Object durchgeführt, dass sich auch in der Oberkomponente befindet und ich kann diese Änderungen direkt dort verwenden. Ein Watcher sollte auch Änderungen erkennen können.
Bei React müßte ich eine callback-funktion mit in die Unterkomponente reinreichen und bei der Änderung diese antriggern, damit die Oberkomponente die geänderten Daten in denen eigenen State wieder übernehmen kann. Also wird in dem Sinne jede Reference, wie sie in Vue.js existiert hätte, durch eine selbst zu implementierende callback-Funktion ersetzt?
Macht das Sinn? Erzeugt es nicht nur mehr Arbeit und Code? Wo genau ist da der Vorteil? Oder habe ich da was falsch verstanden bei React?
Irgendwie werde ich mit React nicht wirklich warm. Es sind so Kleinigkeiten, die mich da stören oder mir das Gefühl geben, einiges wäre unnötig kompliziert in React.
Was man in Java teilweise mit Javassist gemacht hat und man für die Erkennung von Änderungen an Object-Values in JavaScript dringend braucht sind Proxy-Objekte.
Das geht zum Glück an sich ganz einfach.
<html>
<head>
<script type="text/javascript">
var x = {value: ""};
Irgendwie scheint das v-for von Vue.js Probleme zu haben, wenn ein Array z.B. von 5-10 geht und nicht von 0-5. Ich musste jeden Falls erst einmal einen Offset berechnen, um im Array wieder alles von 0 beginnen zu lassen. Dann funktionierte wieder alles.
Da es zu dem Thema "Einkaufswelten Elemente selber bauen mit ExtJS" relativ wenig Hilfe bei Shopware gibt, habe ich mich mal wirklich mit [url=https://developers.shopware.com/developers-guide/custom-shopping-world-elements/#advanced:-adding-a-custom-emotion-component-in-extjs]Hilfe von dem Shopware eigenen Tutorial zu Einkaufswelten Elementen[/ur]) und vielen einzelnen Formus-Beiträgen da durch gekämpft. Ich mag ExtJS immer noch nicht, aber so langsam komme ich wenigstens mit den Components klar. Ist am Ende nicht so viel anders wie Swing oder SWT, nur wird in den Constructoren der Componenten die man erweitert sehr viel "Magic" gemacht auf die man angewiesen ist. Allein die Frage: wie bekomme ich ein einfaches kleines Text-Feld in das richtige FieldSet?
Elemente von Einkaufswelten sind ein wirklich nicht so einfaches Thema, wenn man die reine PHP-Schiene verlässt und mit ExtJS arbeitet. Aber diese Mischung im Vimoe-Element Beispiel finde ich jetzt auch nicht so wirklich toll. Felder hier, Stores da.. man sollte alles auf einen Blick haben und wenn man mit JavaScript arbeitet muss man das Plugin auch nicht öfters neu installieren sondern nur den Cache löschen und das Shopware-Backend neu laden.
Init-Methode einer einfachen kleinen GUI mit einem Feld zur Artikel-Auswahl:
initComponent: function() {
var me = this;
me.callParent(arguments);
Darin sieht man wie man einen eigenen Store mit AJAX-Backend definiert und diesen in der ComboBox verwendet, die man wiederum in den Element-Einstellungen anzeigt. Wenn man schon mal soweit ist, steht einen auf dem Weg zu Einkaufswelten mit eigenen Elementen in Shopware nicht mehr viel im Weg.
Mit der Version kann man nun auch Optout-Links erstellen, um eine Entscheidung zurück zu nehmen ohne den Browser-Storage leeren zu müssen (was ein normaler Besucher sicher nicht alleine hinbekommt).
<a href="#" cookie-optout-link>Doch keine Cookies!</a>
if(val && val > 0){
document.getElementById("cookiequestion").style.display="none";
if(val > 1) {
var event = new Event('cookiequestion_clicked', {value: val, overlay: document.getElementById("cookiequestion")});
document.dispatchEvent(event);
//or do other things here
}
}
//create optional optout-links
var elements = document.querySelectorAll("[cookie-optout-link]");
var func = function(){
return function(){
cookieclose(1);
};
};
for(var i=0; i < elements.length; i++){
elements.addEventListener("click", func());
}
};
Meine Seite hat jetzt auch eine Abfrage, ob Cookies angelegt werden dürfen oder nicht. Es wird nicht nur einfach informiert, dass es geschieht oder nach dem Bestätigen geschehen wird. Der Besucher hat auch die Wahl, ob er mit oder ohne Cookies die Seite besuchen möchte. Ich überlege noch ein Belohnungssystem, für Besucher, die die Anzeigen anzeigen lassen (...was für ein komischer Satz...).
Besuchern die Seite zu verwehren halte ich für falsch. Belohnungen sind besser als Strafen.
Hier eine Plain-JavaScript Lösung, bei der man die Ausführung von AdSense oder Analytics per Event triggern kann. Wenn es einmal bestätigt wurde, merkt sich der Browser die Einstellung und behält das Verhalten bei. Es wird im localStorage gespeichert und dort kann man die Auswahl auch wieder löschen.
if(val && val > 0){
document.getElementById("cookiequestion").style.display="none";
if(val > 1) {
var event = new Event('cookiequestion_clicked', {value: val, overlay: document.getElementById("cookiequestion")});
document.dispatchEvent(event);
//or do other things here
}
}
};
cookieclose(0);
</script>
<p>
Erlauben von Tracking/Cookies?
</p>
<p>
<button onclick="cookieclose(2);">
ja
</button>
<button onclick="cookieclose(1);">
nein
</button>
</p>
</div>
Ich hab so viel liegen, was ich nie weiter entwickeln werde, aber doch verwendet habe und was gut funktioniert. Teilweise auch immer noch gut funktioniert.
Teil 1: cJS
Das kleine JavaScript Framework, mit dem genau so Controller entwickeln konnte wie mit JavaFX.. es was fast eine 1:1-Kopie. MP4toGIF.com nutzt es und es läuft gut. Es hat kein bidirectional-Binding wie Angular. Am Ende wurde eine Lib für AngularJS dafür, die ich auch oft verwendet habe. Das eigene Framework habe ich nie weiter entwickelt, dabei konnte man Controller ondemand per require.js nachladen und so lustige Dinge. Controller konnten Controller anhand des Namens laden.. wie Services in Symfony..
Ich hatte ja gehofft, dass sich AngularJS neben Angular gleichberechtigt halten wird und nicht von diesem ersetzt wird. Sieht wohl aber so aus als würde die Zeit von AngularJS jetzt doch zu Ende gehen (mit 3 Jahren LTS). Also werde ich mir dann doch mal wirklich, nach 1000 mal sich dieses vorzunehmen, genauer ansehen und ausprobieren.
Wenn es mir nicht gefällt gibt es ja noch immer Knockout.js. Lust mein eigenes kleines cJS-Framework doch nochmal weiter zu entwickeln habe ich dann doch nicht. Dem fehlt einfach eine gute Template-Engine und so eine zu schreiben oder einzubauen, wäre etwas zu viel Arbeit.
Mal gucken bei welchen Framework ich am Ende dann landen werde.
Das ist an sich sehr einfach, da man diese Funktion nicht erst in ExtJS einbinden muss, sondern direkt eine globale JavaScript-Variable ansprechen kann.
Eine wichtige Erkenntnis das Code-Element in Shopware Einkaufswelten betreffend ist, dass es Smarty unterstützt. Wer also im HTML-Teil direkt JavaScript verwenden will muss etwas mit den geschweiften Klammern aufpassen. Das gilt besonders, wenn man einfach minimized Code-Snippets von einem Anbieter in die eigene Seite integrieren möchte.
Ich hab mich die letzten Jahre doch etwas schwer getan mit JavaScript-Frameworks, die sich stärker von AngularJS unterscheiden. Knockout gefiel mir sonst auch ganz gut, auch wenn ich es ansich nie produktiv genutzt habe. Es war eben MVVC mit Templating direkt im HTML. Mein eigenes kleines Framework war auch genau so konzipiert und funktioniert bis heute gut in MP4toGIF.com.
Angular 2 sah immer interessant aus, aber irgendwie habe ich es dann doch nicht geschafft mir es mir als anzusehen. Dabei schreckte mich eher Typescript ab, was aber auch ja optional ist. Andere Sprachen und dann alles zu kompilieren mag ich bei JavaScript nicht so sehr.. da waren meine Erfahrungen mit Coffee-Script zu.. ja.. ernüchternd. Die Umgebung zum Entwickeln auf zu setzen ist vergleichbar mit dem Aufwand bei Java oder PHP. Das Debugging ist mit nativen JavaScript sehr viel einfacher gewesen.
Mit Shopware kam dann Ext JS in mein Leben. Seit Groupware und Tine 2.0 habe ich alles versucht diesem Framework aus dem Weg zu gehen. Man kommt damit zu recht, aber es ist echt nicht einfach sich dort einzuarbeiten und mal schnell eine kleine UI zu basteln, ohne sich wirklich einmal mit dem Framework auseinander zu setzen. Angular JS ist da sehr viel einfacher, aber dafür hat man eben auch nicht diese komplexe UI.
Um ehrlich zu sein, würde ich dann aber bei solchen UIs das Ext JS-Framework anderen Frameworks aus dem Desktop-Bereich wie SWT, Swing oder JavaFX vorziehen.
Heute habe ich mich mal durch die Dokumentation und die Beispiele von SAP OpenUI 5 geklickt. Es sieht etwas nach Ext JS aus, aber irgendwie spricht es mich spontan eher an. Nicht wie das erste mal mit AngularJS.. gesehen.. verstanden .. und gleich erfolgreich eingesetzt.Aber mein Gefühl war besser als bei Ext JS .. so ungefähr auf Angular 2 Niveau.
Vielleicht habe ich ja mal die Gelegenheit was damit zu machen. Momentan habe ich weder Projekt noch Zeit dafür. Aber es sieht so interessant aus, dass ich gerne was dafür hätte... gerade der Planning Calendar sieht echt gut aus.
Blog-entries by search-pattern/Tags:
Möchtest Du AdSense-Werbung erlauben und mir damit helfen die laufenden Kosten des Blogs tragen zu können?