Angular.JS ohne $scope

In Angular ist der Scope die technische Implementierung des Viewmodels. Obwohl einfach zu verstehen und verwenden ist angekündigt mit der Version 2.0 darauf zu verzichten. In der Tat ist ein Fehler in der Scope Hierarchie mitunter schwer zu finden.

Folgender Blog Artikel ist rein akademisch und zeigt zwei Wege auf einen Controller in Angular.js zu schreiben bzw Daten deklarativ in HTML zu binden.

   1:  <form id="form1" runat="server" ng-app="app">
   2:          <div ng-controller="myController">
   3:              <input ng-model="person.name" />
   4:<input ng-click="myclick()" type="button" value="click" />
   5:          </div>
   6:   </form>
   7:   
   8:   <script>
   9:         var app = angular.module('app', []);
  10:          app.controller('myController', ['$scope', function ($scope) {
  11:             $scope.person = { name: 'Hannes' };
  12:             $scope.myclick = function () {
  13:             $scope.person.name = "Franz";
  14:              };
  15:       }]);
  16:   </script>

 

Die Scope freie Alternative: Durch die Nutzung der Controller AS Syntax im HTML Teil entfällt $scope als Instanz des Viewmodels. Im Controller kann kann per this auf Methoden und Eigenschaften zugegriffen werden. Über die Extend Methode wird das JavaScript Objekt erweitert.

   1:  <form id="form1" runat="server" ng-app="app">
   2:    <div ng-controller="myController as alias">
   3:        <input ng-model="alias.person.name" />
   4:        <input ng-click="alias.myclick()" type="button" value="click" />
   5:  </div>
   6:  </form>
   7:   
   8:  <script>
   9:     var app = angular.module('app', []);
  10:     app.controller('myController',myCtrl);
  11:     function myCtrl() { };
  12:     angular.extend(myCtrl.prototype, {
  13:              person : { name: 'Hannes' },
  14:              myclick: function () {
  15:              this.person.name="Frnaz";
  16:          }
  17:     });
  18:  </script>

 

Nach einer weile nachdenken, noch eine einfachere Scope freie Version eines Angular Controllers.

   1:  var app = angular.module('app', []);
   2:          app.controller('myController', [function () {
   3:              var vm = this;
   4:              vm.person = { name: 'Hannes' };
   5:              vm.myclick = function () {
   6:                  vm.person.name = "Franz";
   7:              };
   8:          }]);

 

Den gewöhnlichen Teilnehmer einer Angular Schulung überfordert dies eindeutig. In meinem Angular Training bleibe ich bei der Scope Variante.

If you pay Peanuts- you get Monkeys

Gerne zitierte Phrase im Zusammenhang mit mäßig motivierten Mitarbeitern. Unabhängig davon das ich den direkten Zusammenhang zwischen Geld und Leistung bisher in der Praxis nicht erfahren habe, stellt sich die Frage, wie korreliert Bezahlung und Motivation genau. Natürlich hat jeder Mensch Grundbedürfnisse, die erfüllt sein müssen. Aber alles was darüber hinaus, geht schlägt sich nicht immer in ein mehr an Motivation nieder. Manchmal sogar ins Gegenteil.

Aus der Sicht des Arbeitgebers stehen allerdings Kosten und Leistung sehr wohl in einer starken Abhängigkeit. Je nach Region und Geschäftsmodell muss der Ertrag eines Mitarbeiters seine direkte Kosten (ca  Jahresbrutto *1,35) mindestens um den Faktor 2-3 übersteigen um überhaupt in die Gewinnzone zu kommen.  Darin unterscheidet sich rein kaufmännisch betrachtet eine menschliche nicht von einer sonstigen Ressource. Wenn die Rechnung nicht stimmt, ist über kurz oder lang jeder Arbeitsplatz weg. Industriebranchen wie Textil oder Stahl gehen an dieser simplen Formel zugrunde.  Folglich muss jedem Berufseinsteiger bewusst sein, je höher sein Verhandlungserfolg, desto wahrscheinlicher sein Scheitern.

Trotzdem klafft häufig eine Lücke zwischen selbst Wahrnehmung und dem Jahres Brutto. Genau dann kommt aus der Mitarbeitersicht der Widerstand auf. Man ist häufiger krank und bringt in der übrigen Zeit den Tag auf Facebook hinter sich. Braucht sich der Chef nicht zu wundern. If you pay Peanuts – you get Monkeys.

Vergeblich habe ich versucht die Quelle oder den Urheber des Zitats zu finden, um den ursprünglichen Kontext wieder herzustellen. Nun werfe ich mal als Gendanken eine alternative Interpretation auf.

Warum machen Menschen irgendwas, in einer in allen Bedürfnissen übersättigten Zeit? Jedes Jahr ein neues iPhone kaufen? Aber Menschen gehen nach wie vor zur Arbeit, sind bei der Freiwilligen Feuerwehr oder helfen einem Freund beim Haus bauen.

Schlicht weil sie es wollen, also intrinsisch motiviert. Wenn man nun jemanden für etwas was er regelmäßig und gerne macht, kleine Belohnungen in Aussicht stellt, wird das Ergebnis ganz kurz besser und dann bestenfalls gleicht gut funktionieren. Wenn die Sonderleistung (die Erdnuss) gestrichen wird, wird sich die Einstellung durchsetzen, in einer Art Trotzreaktion, die Leistung zu verweigern. Unzählige Studien beschäftigen sich mit der Thematik intrinsische und extrinsische Motivation und deren Auswirklungen. Die Ergebnisse deuten alle in die selbe Richtung. Nur wenn der finanzielle Sonderreiz sehr hoch ist, also deutlich mehr als eine Erdnuss, wird sich jemand auch gesondert bemühen.

Wenn man also einem Menschen für bewertbare Leistungen (zb. Rasenmähen), kleine Bonis gewährt (5€) wird der Mensch zum dressierten Affen, der ohne diese Zuwendung passiv wie ein Affe verharren wird.

Moderne Management Systeme versuchen über Ziele und  Kennzahlen die Mitarbeiter zu managen und versprechen dabei bei Erfüllung entweder sehr viel oder aus Sicht des Mitarbeiters lediglich Peanuts. Das ist eine moderne Art von Zirkusdressur. Dagegen wehren sich moderne gebildete Menschen.

Was denkst Du? Follow up an hannesp@ppedv.de

Bedeutung von Open Source in 2015

Bei einem Bier Gespräch mit Norbert Eder, kam das Thema auf meine aktuelle Meinung zu Open Source. In der Community ist ein Blog Eintrag vor ca zweieinhalb Jahren durchaus heftig diskutiert worden. Fazit daraus, die Verfügbarkeit von Quellcode unter OS Lizenz hat keine Bedeutung für mein Business. In  der Zwischenzeit ist viel passiert, einiges was meine damalige Meinung stützt und anderes was meine Sicht auf die Dinge verändert hat.

Open Source basierte Software ist nicht besser oder sicherer als Closed Source. Dieses Thema hatte ich anlässlich des Sicherheits Problems Heartbleed aufgegriffen. Es fehlt schlicht jeder Beweis für die häufig vertretene These, das hunderte Entwickler den Code prüfen und damit Sicherheitsprobleme sofort auffallen und gelöst werden.

Aus der Sicht als Microsoft Kunde, hat die Veröffentlichung des Quellcodes in der Vergangenheit praktisch meist das Ende des Produktes bedeutet. In jedem Fall wurden Developer Ressourcen abgezogen und die Qualität leidet.

Mein Bedürfnis Quellcode einer Bibliothek zu lesen und vielleicht sogar einen Bug zu fixen hält sich erheblich in Grenzen. Gleiches gilt für Consumer und sicher auf in weiten Teilen für den Enterprise Kunden. Norbert führte ins Feld, das er die Möglichkeit nutzt und auch schon mal Code zurück geleifert hat, neudeutsch contributed. Für mich habe ich dies in den Anfängen von .NET mit ildasm ab und angenutzt um IL Code zurück zu Compilieren und auch mal eine Klasse mit diesem Fragmenten neu zu schreiben. Mit steigender Funktion und Stabilität von .net hat sich dies erübrigt.

Nur ein sehr kleiner Teil der Community ist fähig und willig Code zu contributen. Aus einer konkreten Problemstellung in Angular, kann man auf github nachvollziehen, das es mit der Innovation und den kurzen Zyklen nicht immer so weit her ist. Konkret fehlt eine häufig gewünschte Funktion seit fast drei Jahren.  Angular ist ohnehin ein Spezialfall, weil Google getrieben und bezahlt. Trotzdem wird nur  Support von ca 18 Monaten angekündigt. Im Vergleich dazu bei Microsoft Silverlight zehn Jahre. Wie die Erfahrung zeigt, kann das Ende in jedem Fall schnell und überraschen kommen- in dieser Hinsicht steht es 1:1.

Dabei gibt es durchaus eine Reihe von Leuten die außerhalb des Angular Projektes den Aufwand getrieben haben und dieses fehlende Feature entwickelt haben. Dazu gehöre auch ich. Allerdings findet sich meine Lösung als Blog Beitrag, schlicht weil ich den Aufwand mit Github nicht treiben möchte und auch Zweifel habe ob meine Lösung wirklich optimal ist. Was ich definitiv nicht brauche ist emotionale Diskussion bis hin zum Shitstorm meiner Arbeit, Norbert Eder fordert in diesem Kontext mehr Mut und verspricht sich davon die persönliche weiter Entwicklung.

Welche Auswüchse die Selbstorganisation von Open Source Projekten annehmen kann, sieht man an Node.js oder Angular 2. Erst passiert längere Zeit nichts, dann gibt es eine Abspaltung, Fork genannt und keiner weis so recht, wie es weiter geht. Durchaus häufig Bloggen Core Entwickler Ihren Unmut und die Beweggründe für Ihren Ausstieg, was dem Projekt nicht zuträglich ist. Natürlich kann das bei Unternehmen auch passieren, allerdings sind diese für Ihre Produkte haftbar. Das kann richtig ins Geld gehen. Open Source Projekte sind da fein raus, da haftet niemand. Mitarbeiter sind überdies Vertraglich zur Verschwiegenheit verpflichtet.

OS Bibliotheken werden in der Regel völlig Enthusiastisch von der Community aufgenommen  und über Nacht zum defacto Standard deklariert. Wer Zweifel äußert, hat nicht verstanden oder sich noch nicht hoch genug in die spirituellen Welten begeben.

Wenn Monate später Design oder Performance Ziele nicht erreicht wurden, wird still und heimlich eine neue JavaScript Sau durchs Dorf getrieben. Da bleibt keine Zeit für Manöver Kritik und Analyse des Scheiterns. Hintergründe sind bestenfalls einer Handvoll Insidern bekannt.

In einem User Group Vortrag von Mike Bild zum Thema Microservices, fiel nebenbei die Bemerkung “mit dem alten Zeugs, bekommst schlicht keine Entwickler mehr”.  Das geht sogar soweit, das jeder Service mit einer eigenen Technologie gebaut werden kann. Ein Gedanke der sich mit der generellen Veränderung des Weltbildes der heutigen Berufseinsteiger gut deckt. Mann will selbstbestimmt leben. Ein Pflichtenheft degradiert dabei zum Code Monkey. Das bedeutet das es Technologie Entscheidungen gibt, die die Anzahl der Bewerber erheblich steigern können. Richtig- die ganze Java Script Welt scheint  aus diesen Nektar zu sprießen. Die agilen Methoden liefern genau dafür Management freie Umgebungen. Jeder tut was er kann und will. Der Kontrollverlust ist Horrorvorstellung für fast jeden Entscheider.

Microsoft setzt seit einigen Jahren auf Open Source, weit über das Ajax Control Toolkit hinaus. Man fragt sich warum. Wo wird dadurch Geld verdient? Speziell da sich der Redmonder Hersteller diesen Projekten regelrecht anbiedert und dabei die gestandenen Microsoft Kunden gefühlt im Regen stehen lässt. Seit Windows 8, also schon vier Jahre, werden JavaScript und co propagiert. Der einzige Zweck kann nur sein, Teile der nicht Microsoft Welt abzuholen. Gefühlt ohne große Resultate, dafür aber plötzlich mit einem Migrationspfad, der weg von Microsoft führt. In der Tat sind einige MVP’s in der Zwischenzeit stolze Mac User mit veränderten Entwicklungsfocus.

Gern zitiertes Argument pro Shared und damit Quell Offener Software ist der letztendlich verlorene Kampf der Microsoft Encarta vs Wikipedia. In erster waren viele Entwickler und Autoren beschäftigt und bezahlt. Wikipedia arbeitet kostenfrei und sogar (fast) ohne Werbung.

image

Auch Wikipedia kennt die Community üblichen Grabenkämpfe zwischen der für Reinheit kämpfenden Elite und anderen Autoren. Auch Wikipedia braucht Geld. Das allerschlimmste aber, es ist nur Platz für ein einziges Wikipedia. Es kann keine Konkurrenz und damit auch keine Innovation mehr gegeben. Die Zukunft wird eine Welt der Monopole bringen.

Die Microsoft Openess gipfelt in der Veröffentlichung von Kern Teilen des .NET Frameworks, Ich könnte meinen ASP.NET 5 Code nun teilweise auf einem iOS hosten. Warum sollte ich das? Ich würde mir mehr wünschen, das Silverlight auf iOS oder Android läuft. Aber das ist eine andere Geschichte.

Die neue selbstbestimmte Generation findet also sich und den Shared Gedanken in Open Source wieder. Diese Mitarbeiter sind damit intrinsisch motiviert und schaffen auf Vertrauensbasis. Soweit das Ideal. Allerdings wechselt Motivation und unterliegt der Tagesverfassung. Man hat Sorgen, Krankheit  oder einen blöden Chef der das alles nicht versteht. Produkte müssen trotzdem fertig werden. Den durchaus nicht neuen agilen Gedanken findet man als Vorgehensmodell in SCRUM definiert. Den größten Vorwurf den ich z.B. Scrum mache ist, das von einer idealen Welt ausgegangen wird. Der krank feiernde Kollege existiert darin nicht.

Auch Open Source enthält Übles und wir haben keine Mechanismen damit umzugehen. Paket Manager werfen gnadenlos zehntausende Zeilen Code in das Projekt. Selbst wenn man alles validieren würde, erlauben es die extrem kurzen Zyklen nicht, den Code Fehlerfrei zu halten. Enterprise Kunden stiegen dann aus npm und nuget aus und pflegen ihren veralteten Open Source Code selber weiter. Persönlich erwarte ich den ein oder anderen Sicherheitsgau auf uns zukommen.

Allerdings hat Open Source wesentliche Impulse geliefert um in diesem Umfeld überhaupt Software produzieren zu können. Das öffnen einer Issue List für jedermann, die kurzen Zyklen und das ggf. direkte Eingreifen in den Code findet man in Wasserfall basierenden Modellen nirgends. Diese dafür entwickelten Konzepte erlauben es nun viel schneller Produkte in den Markt zu bringen. Der vorläufige Höhepunkt aus der Open Source Community ist DevOps mit Vermischung von Administration und Programmierung. Die Release Zyklen gehen dabei bis in den Minutenbereich und erlauben dann kaum noch automatisierte Tests.  Codieren sozusagen am offenen Herzen. Nichts desto trotz sind die Vorgehensweisen essentiell beim Fixen on Hot Bugs in stark genutzten Web Anwendungen. Einen mehrstündige Down kann sich eine Azure Cloud nicht leisten.

Open Source wird weiter das Business aufrollen. Getrieben vom Trend der Shareconomy. Persönlich sehe ich das nur als schmalen Aspekt einer tiefgreifenden gesellschaftlichen und wirtschaftlichen Veränderung. Welche Risiken und Veränderungen sich daraus ergeben, lässt sich nicht einmal im Ansatz abschätzen. Bei weiten Teilen der Community spielt Risiko Betrachtung aktuell gar keine Rolle mehr. Letztendlich bleibt auch die Frage offen wie unsere Geschäftsmodelle der Zukunft aussehen werden, wenn plötzliche keine Software Lizenzen  mehr verkauft werden.

Boostrap Toogle Switch mit Angular Direktive

Was Jquery Mobile mit dem Flipswitch kennt, sucht man bei Bootstrap vergeblich.

image

Da es ziemlich naheliegend ist, fordert die Community auf Github von Bootstrap seit drei Jahren das Feature. Irgendwie vergeblich. Da Open Source, kann man das natürlich selber schreiben und ins Projekt einchecken. Viele tun das scheinbar nicht. Man findet jede Menge Lösungen offsite, die allerdings in Funktion und Qualität nicht ganz den Ansprüchen genügen. Also selber machen.

Das Layout könnte im HTML Code z.B. so gelöst werden

   1:  <div class="btn-group">
   2:       <a class="btn btn-xs btn-primary active">Wert</a>
   3:       <a class="btn btn-xs btn-default">Wert2</a>
   4:  </div>

Ist optisch nicht ganz ein Flipswitch, aber leicht anpassbar.

image

Für den Zustandswechsel wird ein Stück JavaScript benötigt, das die Klassen btn-primary und btn-default austauscht.

Hier wird aber weiter gedacht. Der Wert soll an ein Viewmodel eines Angular.js Controllers gebunden werden.

   1:    .controller('myController', ['$scope', function ($scope) {
   2:                 $scope.wert = true;

 

Der HTML Teil wird mit einer Angular Direktive erstellt. Als Parameter werden die beiden Beschriftungen übergeben.

   1:  <div class="btn-group" 
   2:     my-toggle my-text1="meins" my-text2="public" model="wert">
   3:  </div>

 

In meinem Angular Trainings lernt man die genauen Details zu Direktiven. Auf einige Angular Stolpersteine soll hier aber hingewiesen werden.

Mit dem Template wird HTML Code in der Page erzeugt, der die beiden Buttons enthält. Komplizierter ist die Gültigkeit des Scope, der das Viewmodel aus dem Controller hält und letztendlich den checked Wert enthält. Wie kann man aus einer Direktive auf den Scope des Controllers zugreifen und diesen auch verändern? Da es mehrere geschachtelte Scopes gibt, somit auf den Parent Scope.

Mit Chrome und der Batarang Erweiterung kann die Internas der Scope Hierarchie auch darstellen.

image

image

Im HTML Code wurde vorher das Attribut model eingeführt, das auf die Property wert (also $scope.wert) bindet. Leider verhält sich die Bindung auf den my-text obwohl optisch ident völlig anders.

In der Direktive wird gesteuert, welche Attribute (@) und Bindungen (=) in den privaten Scope übernommen werden. Nun kann in der Click Funktion des DIV! der Parent Scope ($scope.wert) per Child Scope (scope.model) geändert werden, weil das = eine zwei Wege Bindung bewirkt.

   1:  .directive('myToggle', function () {
   2:         return {
   3:                    restrict: 'A',
   4:                      scope: {
   5:                             model: '=',
   6:                             myText1: "@",
   7:                             myText2: "@"
   8:                         },
   9:                         template: '<a class="btn btn-xs active" 
ng-class="model ? \'btn-primary\' : \'btn-default\'">{{myText1}}</a>'
+
  10:                        ' <a class="btn btn-xs " 
ng-class="model ? \'btn-default\' : \'btn-primary\'">{{myText2}}</a>'
,
  11:                         link: function (scope, element, attr) {
  12:                             element.bind('click', function () {
  13:                                 scope.model = !scope.model;
  14:                                 scope.$apply();
  15:                             });
  16:                 }
  17:           }
  18:     })

Bootstrap mehrfach Navbar

Einige Zeit habe ich über der Usability einer Web Anwendung gegrübelt. Aktuell verwenden wir das Projekt um Realtime Feedback, vor während und nach Konferenz Sessions, zu bekommen. Die Idee ist einen lernen-wissen-teilen Zyklus weit über die eigentliche Konferenz hinaus zu etablieren.

Nächste Woche auf der GUI&DESIGN in Berlin, wird das Projekt wieder eingesetzt. Da wir unter anderem mobile Devices mit dieser Web App adressieren, folgt das UX dem responsive Design Paradigma. Framework ist Bootstrap.

Jede Konferenz Session kann einzeln von Teilnehmer  mit bis 5 Sternen bewertet oder mit Text Kommentaren versehen werden. Das Problem ist der begrenzte Bildschirm. Wie präsentiert man bis zu 30 Sessions gleichzeitig auf einem Smartphone? Nach einem Pair UX Review mit Martin Hoppe von Maximago, kam der Gedanke auf, das von der Bedienung wie eine Bootstrap Navar zu lösen.

Damit waren folgenden Anforderungen definiert

  • Mehrstufige Navbar
  • Navbar Toogle Button dauerhaft anzeigen
  • Menüpunkte nur bei Drop Down
  • Menü schließen bei Auswahl
  • mehrspaltiger Navbar Collapse Bereich

Da fertige UI auf einem iPhone Emulator

image

Und der nicht ganz perfekte multi drop down Navbar Anwendungsfall

image

Die Steuerung des AufZu einer Navbar, wird über ein UI Element mit dem Attribut data-toggle ausgelöst. Das Ziel ist eine Klasse oder ID eines DIV Elements, hier als collapse2 bezeichnet um einen Unterschied zu navbar-collapse des Top Menüs zu haben. Der Z Index  ermöglicht der Top Navbar sich über die zweite Reihe Navbar zu entfalten. Der Abstand top entspricht der Höhe der Top Navbar.

   1: <nav class="navbar navbar-inverse navbar-fixed-top always-open" 
style="top: 50px;z-index:999;">
   2:    <div class="navbar-header">
   3:      <a class="navbar-brand" href="#">Room {{target}}</a>
   4:        <button type="button" class="navbar-toggle"
   5:           data-toggle="collapse" data-target=".navbar-collapse2">
   6:           <span class="icon-bar"></span>
   7:           <span class="icon-bar"></span>
   8:           <span class="icon-bar"></span>
   9:       </button>
  10:     </div>
  11:              
  12:  <div class=" navbar-collapse2 collapse" >

Die ASPX Seite setzt sich aus einer Masterpage und einer Content Page zusammen. In der Content Page (gern auch View) wird das CSS  von Bootstrap in einem Style Block überschrieben und ergänzt. Ziel ist es das Verhalten der Second Navbar zu ändern (always-open). Diese ist dann nicht mehr Responsive, sondern verhält sich so wie eine Navbar im Smart Device Modus.

   1:  .navbar {
   2:     margin-bottom: 0 !important;
   3:          }
   4:  .navbar.always-open {
   5:     border-radius: 0;
   6:           }
   7:  .navbar.always-open .navbar-header {
   8:     float: none;
   9:           }
  10:  .navbar.always-open .navbar-toggle {
  11:     display: block;
  12:           }
  13:  .navbar.always-open .navbar-collapse {
  14:     border-top: 1px solid transparent;
  15:     box-shadow: inset 0 1px 0 rgba(255,255,255,0.1);
  16:            }
  17:  .navbar.always-open .navbar-collapse.collapse {
  18:     display: none !important;
  19:            }
  20:  .navbar.always-open .navbar-nav {
  21:     float: none !important;
  22:     margin: 7.5px -15px;
  23:             }
  24:  .navbar.always-open .navbar-nav > li {
  25:             float: none;
  26:             }
  27:  .navbar.always-open .navbar-nav > li > a {
  28:     padding-top: 10px;
  29:     padding-bottom: 10px;
  30:             }
  31:  .navbar-collapse2 {
  32:     padding-right: 15px;
  33:     padding-left: 15px;
  34:     overflow-x: visible;
  35:     -webkit-overflow-scrolling: touch;
  36:     border-top: 1px solid transparent;
  37:     -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
  38:     box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
  39:           }
  40:   
  41:  body {
  42:     padding-top: 100px !important;
  43:          }

 

Die beiden Attribute Data-Toggle und data-target werden dann in den einzelnen Listen Einträgen verwendet, um die Navbar nach Selektion auch wieder einzuklappen. Die Navbar Collapse Liste setzt sich dabei in der Regel aus UL und LI Elementen zusammen. Die LI Element werden einfach in der Breite geschrumpft. Für drei  spaltig auf einen Wert <33% und auf block formatiert.

   1:  <li  title="<%#Item.roomname%>" style=" width:32.6%; display: inline-block">
   2:  <a href='/chat#<%#HttpUtility.UrlEncode(Item.shortname)%>'
   3:  data-toggle="collapse" data-target=".navbar-collapse2"

 

und so sieht der normale Browser Benutzer die Web App

image

Viel Freude damit.

easy Datenbindung MVVM und XAML

Ich erinnere mich noch recht gut an meine ersten Silverlight Schulungen. Das Thema zwei Wege Datenbindung und die Benachrichtigungsevents ans Userinterface, war für den Kursteilnehmer immer etwas mühsam. Nun komme ich aus einem Vortrag auf der #ADCX und hab ganz Beiläufig fody kennen gelernt. Und die Welt ist schöner geworden.

Zur Erinnerung: Um einem Model die Fähigkeit zu geben, eine Änderung der Daten dem User Interface mitzuteilen, muss das Interface INotfiyPropertyChanged implementiert werden. Pro Eigenschaft muss dann das ProperChanged Event, mit dem Namen des Propertys als String Argument, ausgelöst werden. Mal abgesehen von der Tipperei, eine perfekte Fehlerquelle. Mit .net 4.0 wurde dann das CallermemberAttribut eingeführt, das dem Compiler erlaubt, den Wert zuzuweisen. In Silverlight 5 muss man einen Trick verwenden, um das Attribut überhaupt nutzen zu können.

   1:  <AttributeUsageAttribute(AttributeTargets.Parameter, Inherited:=False)>
   2:  Public NotInheritable Class CallerMemberNameAttribute
   3:      Inherits Attribute
   4:  End Class

Ohne obigen Code wird folgender VB.NET Code in einem Silverlight Projekt nicht kompilieren

   1:  Public Class person
   2:      Implements INotifyPropertyChanged
   3:      Property id As Integer
   4:      Private _name As String
   5:      Public Property name() As String
   6:          Get
   7:              Return _name
   8:          End Get
   9:          Set(ByVal value As String)
  10:              _name = value
  11:              OnPropertyChanged()
  12:          End Set
  13:      End Property
  14:   
  15:      Protected Sub OnPropertyChanged(<CallerMemberName> 
Optional propertyName As String = Nothing)
  16:          RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
  17:      End Sub
  18:      Public Event PropertyChanged(sender As Object, 
e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
  19:  End Class

 

Die Zwei Wege Bindung wird nur für das Property name implementiert. Es muss die Langform mit Getter und Setter verwendet werden um in letzteren das Änderungs Event auszulösen (Zeite 11). Der Compiler ersetzt in Zeile 11 den Wert des Parameters propertyName mit “name”.

Es gib wohl Menschen die sich den Gedanken der Compiler Services noch tiefer zu Gemüte geführt haben. Auf Basis von Fody existiert ein Plugin für NotifyPropertyChanged, das man sich per Nuget in seine Visual Studio Projekt installieren kann.

image

Ab jetzt ist es nur noch geli einfach. Aus je zehn Zeilen Code wird eine. Es reicht eine Klassenattribut einzufügen und die verkürzte Propertysyntax.

   1:  <ImplementPropertyChanged>
   2:  Public Class person
   3:      Property id As Integer
   4:      Property name As String
   5:  End Class
Der Compiler erzeugt daraus im wesentlichen die Langversion des Codes, wie im vorigen Beispiel demonstriert.

PS fast auf den Tag genau vier Jahre sind vergangen seit Bob Muglia beiläufig Silverlight für Tod erklärte. Nur drei Monate später musste Bob der damalige Chef von Server und Tools seinen Stuhl räumen. HTML5 reicht auch heute noch bei weitem nicht an Silverlight heran.

Expression Blend UX Guides

Es ist wahnsinnig einfach schlechtes Design zu entwerfen. Aber es ist auch relativ einfach gute User Interfaces zu bauen, wenn man die Grundregeln kennt. Um ein klares Layout (Clean Layout) zu erstellen braucht das UI ein Schema. Mit einem typografischen Grid Layout kann man die UI Elemente wie Text und Bilder strukturieren und ausrichten.

(Quelle Wikipedia)

Visual Studio 2013 erlaubt es ein Raster einzublenden und neu erzeugte Controls an den unzähligen Führungslinien auszurichten.

image

Expression Blend für Visual Studio 2013 kann da schon einiges mehr. Wenn man im Designer vom Lineal per Maus Drag und Drop auf das UI zieht entstehen blaue Führungslinien. Diese werden Rulers und Guides genannt.

image

Dieses UI Schema kann man sogar speichern um es später in anderen XAML Seiten wieder zu verwenden. Im Menü View – Manage Guides auswählen.

 image

Besonders praktisch, Blend bietet auch eine Reihe von vordefinieren Guidelines  zur Auswahl. Für eine Windows Store App (vormals METRO) sind das

  • BasicPage
  • FileOpenPicker
  • GroupDetailPage
  • GroupedItemsPage
  • HubPage
  • ItemsPage
  • SearchResultsPage
  • SettingsFlyout
  • ShareTargetPage
  • SplitPage

Die GroupItemsPage Vorlage

image

Expression Blend für Visual Studio 2013 ist der Nachfolger von Blend 4.0. Damit lassen sich WPF, Silverlight und WIndows 8.1 Apps (HTML und XAML) Designen. Expression Studio 4 wurde komplett eingestellt. Der Nachfolger ist direkt in Visual Studio integriert und benötigt keine separate Lizenz. Mehr zu UX Design gibt es auf der GUI&DESIGN Konferenz in Berlin. Der Autor gibt auch 2-tägige Blend Schulungen.

Layoutrounding mit Expression Blend

Pixel sind niemals rund. Wenn man es genau nimmt sind die realen Pixel quadratisch. Es gibt eine Reihe von Fällen indem die Umrechnung der virtuellen Pixel in die physikalisch vorhandenen erhebliche Probleme aufwirft. Man kann keinen halben Pixel füllen. Windows versucht alles erdenkliche solche Effekte zu minimieren. Dazu kommt das mit dem High DPI Displays zumindest dieses Problem, für das ungeübte Auge nicht zu erkennen ist. Die Funktion nennt sich Layoutounding. Damit wird ein mathematisch halb zu füllendes Pixel ganz gefüllt.

In XAML bestimmt das Container Element wie die Inhalte gerendert werden. Silverlight macht dies automatisch, in WPF ist diese Funktion deaktiviert. Folgendes WPF Beispiel zeigt di Problematik in Expression Blend für Visual Studio 2013.

   1:  <Canvas x:Name="LayoutRoot" Background="White"  UseLayoutRounding="True">
   2:  <Ellipse Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="10" 
   3:  Stroke="Black" VerticalAlignment="Top" Width="10" 
StrokeThickness="0.2" Canvas.Left="245" Canvas.Top="174"/>
   4:  <Ellipse Fill="#FF1717F1" HorizontalAlignment="Left" Height="8" 
   5:  StrokeThickness="0.2" VerticalAlignment="Top" Width="8" 
Canvas.Left="246" Canvas.Top="175"/>
   6:  </Canvas>

Es gibt einen Aussenkreis mit nur 1 Pixel Abstand, der mit einer 0,2px Linie umrandet ist. Nimmt man Silverlight als Projektype sieht das Ergebnis im Visuellen Designer wie erwartet aus. Hier im Bild auf 6000% gezoomt.

layoutrounding2

Alles wie es sein soll. Wenn man den gleichen XAML Code in ein WPF Projekt kopiert und das Attribut UseLayoutRounding  nicht oder auf false gesetzt hat sieht das Ergebnis wie folgt aus

layoutrounding1

Dies mag auf den ersten Blick ein sehr konstruiertes Beispiel sein, soll aber verdeutlichen, das auch bei WPF Pixelgenaues Layout besonderer Aufmerksamkeit bedarf.

Themen wie diese, können Sie auf der GUI&DESIGN Konferenz mit den Experten diskutieren.

Angular Controller as

Wenn ich so darüber nachdenke, gibt es in Angular.js mindestens immer zwei Möglichkeiten eine Aufgabe zu lösen. Eine Direktive kann eine Funktion oder ein JSON Objekt zurück liefern. Ein Service kann eine Factory oder ein Service sein. Alles leicht verwirrend. In die Kategorie, muss das auch noch sein, fällt die Scope Freiheit eines Controllers.

Üblicherweise wird jedem Controller der Scope per Dependency Injection üergeben und damit eine Singleton Instand erstellt. Es gib auch eine Alternative Variante ohne $Scope.

Dabei wird eine “Controller as” Syntax eingesetzt, die sozusagen einen Alias erzeugt, der dann als Objektträger herhalten muss.

   1:    <div ng-controller="mycontroller as hannes">
   2:          {{hannes.count}}
   3:          <button ng-click="hannes.click()">plus</button>
   4:    </div>
   5:    

 

Der zugehörige Controller wird aber gänzlich anders codiert. Zunächst wird wie üblich die App als Modul erzeugt und darin ein Controller definiert, der auf eine Controller Methode verweist. Dieser ist allerdings Parameterlos. Die Propertys des Scopes werden per this erzeugt. Das fühlt sich aus C# Entwicklersicht fast natürlich an.

JavaScript typisch, wird per Prototype das bestehende Objekt um eine Funktion, hier click, erweitert.

   1:    var App = angular.module('App', []);
   2:    App.controller('mycontroller', myfunction)
   3:    function myfunction() {
   4:        this.count = 0;
   5:      };
   6:   myfunction.prototype.click= function () {
   7:       this.count++;
   8:     };

 

Auch wenn ich die Variante mit $scope optisch weniger gelungen finde, werde ich wegen der Konsistenz innerhalb von Angular diesen Weg nicht verwenden.

Fileupload mit Angular.JS

Eigentlich müsste es heißen: Der Kampf des Dateiuploads gegen Angular.JS. Das Framework unterstützt uns dabei in keiner Weise. Wir müssen es an mehreren Stellen sogar austricksen.

Die Programmieraufgabe umfasst folgende Bauteile

  • Webservice, der die Datei entgegennimmt und speichert
  • HTML User Interface mit Input Type File
  • JavaScript Code für Ajax und Scope

Um volle Kontrolle über die hochgeladenen Dateien zu haben, bezüglich Typ, Größe oder Speicherort, bleibt nur ein Service am Web Server. In diesem Fall ist dieser per ASP.NET Web API und VB.NET erstellt.

   1:  Public Class fileuploadController
   2:      Inherits ApiController
   3:      <HttpPost>
   4:      Public Sub UploadFile()
   5:          If HttpContext.Current.Request.Files.AllKeys.Any() Then
   6:              Dim f = HttpContext.Current.
Request.Files("UploadedImage")
   7:              If f IsNot Nothing Then
   8:                  Dim fp = Path.Combine(
HttpContext.Current.Server.MapPath("~/upload"),
Path.GetFileName(f.FileName))
   9:                  f.SaveAs(fp)
  10:              End If
  11:          End If
  12:      End Sub
  13:  End Class

 

Das UX wird aus optischen Gründen auf einen Button reduziert, der den Betriebssystem-File-Open-Dialog öffnet und beim Schließen den Upload anstößt. Dadurch können wir das UI per Bootstrap schöner stylen, da die leere Textbox des Type File nicht angezeigt wird. Allerdings muss ein zweiter Button das Click Event des Fileupload-Buttons auslösen.

Das geschieht in Zeile 6 und zeigt bereits eine Reihe von Problemen mit Angular. Eigentlich sollte der Onclick-Handler nicht im HTML-Code auftauchen. Die Alternative ist eine Angular-Direktive mit rund 15 Zeilen Code, mit der dann auch noch ein zusätzliches Attribut in das Input-Element gelegt werden muss. Das ist mehr Aufwand und der Code ist dadurch leider auch nicht besser lesbar.

Außerdem kann man leider die DOM-Selector-Eigenschaften nicht verwenden, auch wenn ein angular.element(‘#id’) uns dies glauben lässt. Damit dieser Code funktioniert, muss erst noch jQuery eingebunden werden, da JQLite diese Selektoren nicht beinhaltet. Dann könnte man aber gleich $(‘#id’) nutzen. Es drängt sich die Frage auf, warum das komplette jQuery Framework überhaupt Overhead erzeugen soll, wenn es die benötigte JavaScript-Funktion bereits gibt. Also wird hier document.querySelector verwendet, um das Click Event durchzureichen.

Noch schlimmer wird es, wenn man aus normalem JavaScript auf das Angular Framework zugreifen muss. Dies ist hier nötig, da die Value Eigenschaft, die die ausgewählte Datei beinhaltet, nicht per ng-model bindbar ist. Auch für dieses Problem lässt sich eine umfangreiche Direktive schreiben oder einfach das OnChange-Event auf ein Event des $Scope durchreichen (Zeile 4)

   1:  <body  ng-controller="uploadController">
   2:      <label for="fileUpload"></label>
   3:      Select <input id="fileUpload" type="file" 
style="visibility:hidden;position:absolute;top:0;left:0"
   4:         onchange="angular.element(this).scope().onChange(this)" />
   5:   
   6:      <input id="btnUploadFile" type="button" value="Upload File"
onclick="document.querySelector( '#fileUpload').click()" />
   7:  <img id="progress" src="img/upload-indicator.gif"  ng-show="warten"/>

 

image

Zusätzlich wird noch ein animiertes GIF verwendet, das die Uploadaktivität visualisiert und hier durchaus elegant per ng-show an die Eigenschaft Warten des $scope gebunden wird.

Zuletzt muss noch die eigentliche Upload-Logik geschrieben werden. Dazu wird ein Formdata-Objekt erstellt und mit den Datei-Meta-Informationen und dem Stream gefüllt. Dann wird per $http der Post auf den Upload-Service angestoßen. Um ein Problem mit Angular und dem benötigten Multipart-Formdata-Header zu umgehen, fügen wir in Zeile 17-19 Workaround-Code ein.

   1:  var app=angular.module("App",[])
   2:    .controller("uploadController", function ($scope,$http) {
   3:     $scope.warten = false;
   4:     $scope.onChange = function (dateien)
   5:      {
   6:        $scope.warten = true;
   7:        var file = dateien.files[0];
   8:        var data = new FormData();
   9:        data.append('UploadedImage', file);
  10:        data.append('FileName', file.name);
  11:        data.append('fileSize', file.size);
  12:        data.append('fileType', file.type);
  13:   
  14:        $http
  15:          .post('/api/fileupload/uploadfile' , data,
  16:                 {
  17:                   transformRequest: angular.identity,
  18:                    headers: { 'Content-Type': undefined }
  19:                  })
  20:                 .success(function () {
  21:                       $scope.warten = false;
  22:                  })
  23:                 .error(function () {
  24:                       $scope.warten = false;
  25:                          alert('error');
  26:                      });
  27:              };
  28:     });

Sie möchten mehr erfahren und in die Programmierung mit AngularJS einsteigen? Dann sind Sie bei diesem AngularJS Training richtig.“

Training, Schulung, Sharepoint

Month List