W

Passaggio dati tra controller Angular tramite servizio

Molto spesso nei nostri progetti c’è la necessità di passare dati fra diversi controller; una delle soluzioni che ho visto adottare spesso è quella di utilizzare emit / broadcast dalla parte di chi il dato lo vuole condividere e registrare uno o più listener dalla parte dei controller che devono essere notificati di questo nuovo dato.

Il tipo di approccio sopra pò presentare qualche criticità, sia nel capire il codice per chi non l’ha scritto (e anche per chi l’ha scritto, se passa molto tempo) sia per la sua implementazione; se abbiamo il controller A che deve condividere il dato xx con il controller B ed entrambi possono modificare xx, ci si trova  a dover creare un emit sia sua A sia su B e, allo stesso modo, un listener sia su A sia su B. Infine, una parola anche sulla testabilità: con tale approccio si può testare, ma anche la parte di testing diventa più difficoltosa e poco lineare.

Dopo questa premessa, vi propongo un approccio diverso, sfruttando un service per scambiare i dati e mantenere lo stato; tutto questo è possibile perchè in Angular i service sono singleton, quindi una volta istanziati dal container DI la stessa istanza viene passata nel costruttore di ogni oggetto che ne faccia richiesta tramite dipendenza nel costruttore.

Nel codice allegato (che trovate alla fine) c’è un esempio funzionante di quanto vi sto dicendo; ve lo descrivo brevemente di seguito.

Abbiamo una semplice pagina con una input box, un pulsante ed una lista.

L’input box e il pulsante sono controllati dal controller First mentre la lista dal controller Second (si, lo so, poca fantasia… ); l’utente può inserire una stringa non vuota nell’input e, premendo il pulsante, aggiungerla alla lista che viene poi mostrata da Second.

Entrambi i controller First e Second hanno una dipendenza verso il service myService (sempre molta fantasia…), che mantiene una collezione delle stringhe.
In particolare i diversi attori:

FirstController

  1. Ha la proprietà nuovoDato, in bind con la input
  2. Espone il metodo addDato in bind con il pulsante; quando premuto, chiama il metodo addDato di myService, passando come argomento nuovoDato

SecondController

  1. Espone la funzione dati, in bind con l’elemento <li> tramite la direttiva ngRepeat. La funzione dati, al suo interno, richiama il metodo getList di myService, che ritorna la collezione di stringhe

MyService

  1. Ha la proprietà privata myData che mantiene al suo interno la lista delle stringhe (si tratta di un array, inizializzata con già un dato al suo interno “Dato già presente…”)
  2. Espone il modo addDato, che prende in ingresso una stringa e la aggiunge all’array myData
  3. Espone il metodo getList che ritorna la lista delle strighe (array myData)

Il tutto è molto semplice, come potete vedere, ma anche lineare; un unico punto in cui il dato viene mantenuto e aggiornato; i controller non fanno altro che chiamare i metodi del servizio senza doversi preoccupare di notifiche e gestione di eventi.

Tutto il codice client è scritto in TypeScript

Soluzione Visual Studio 2015

Share Button
 
W

JavaScript – Rendere testabile codice già esistente ma NON testabile

Sono appena “caduto” su codice JS scritto in questo modo:

angular.element(document).ready(function () {
    // Fatto così è un casino da testare!!
    angular.module("ModuloPerCostanti", [])
        .constant("parametri",
        {
            costanteUno: $("#parameters").data("costante-uno"),
            costanteDur: $("#parameters").data("costante-due")
        });

    angular.module("ModuloPrincipale", ["ModuloPerCostanti", "ModuloPerServizi", "ModuloPerDirettive", "ngSanitize", "ngResource"])
        .filter("filtroUno", function () {
            return function (data) {
               //DoSomething
            }
        })
        .filter("formatPrezzo", function () {
            return function (data) {
                //DoSomething                
            };
        })
        .controller("ControllerPrincipale", ["$rootScope", "$scope", "$http", function ($rootScope, $scope, $http) {
                // DoSomething
        }])
        .controller("ControllerSecondario", ["$rootScope", "$scope", "$compile", "$http", "$window", "$timeout", "$filter", "$sce", function ($rootScope, $scope, $compile, $http, $window, $timeout, $filter, $sce) {
            //DoSomething
        });
});

Scritto in questo modo, non sarà testabile a meno di scatenare l’evento “documentReady” e far inizializzare i moduli, i controller, i filtri, le direttive etc… (cfr: http://bittersweetryan.github.io/jasmine-presentation/#slide-17)

Questo perché? Jasmine (framework JavaScript utilizzato per il testing) carica i moduli angular in questo modo:

angular(“ModuloPerCostanti”) // Cercherà ma non troverà il modulo ModuloPerCostanti

angular(“ModuloPrincipale”) // Cercherà ma non troverà il modulo ModuloPrincipale

Purtroppo Jasmine non troverà alcun modulo, perché quella parte di codice, che definisce i moduli, viene avviata solo durante l’evento document.ready.

Il codice è scritto in quel modo perché dipende dell’HTML della pagina, in particolare la parte di “constant” richiede che il documento sia completamente caricato (di fatto quelle non sono costanti… se fosse C# non ci permetterebbe mai di compilare come costante qualche cosa di non noto a compile time); tralasciando tutto questo, come renderlo testabile senza stravolgerlo? (tenete conto che quando bisogna “rendere testabile” un codice qualcosa non funziona; test a parte, significa che stiamo usando un approccio poco lineare difficile da capire, manutenere e non è detto funzioni sempre).

Basta un piccolissimo accorgimento,utilizzando la notazione dei NameSpace javascript, in modo da minimizzare possibli conflitti:

  1. Dichiariamo il nostro nameSpace
  2. Creiamo una funzione Init che contenga tutto il nostro codice, con la notazione dei NameSpace:
    var NostroNameSpace; // Dichiariamo ma non inizializziamo il namespace
    (function(tempNameSpace){ // Funzione anonima autochiamante
        tempNameSpace.Init = function(){ // al parametro tempNameSpace viene agganciata la funzione Init
        angular.module("ModuloPerCostanti", [])
            .constant("parametri",
            {
                costanteUno: $("#parameters").data("costante-uno"),
                costanteDur: $("#parameters").data("costante-due")
            });
    
        angular.module("ModuloPrincipale", ["ModuloPerCostanti", "ModuloPerServizi", "ModuloPerDirettive", "ngSanitize", "ngResource"])
            .filter("filtroUno", function () {
                return function (data) {
                   //DoSomething
                }
            })
            .filter("formatPrezzo", function () {
                return function (data) {
                    //DoSomething                
                };
            })
            .controller("ControllerPrincipale", ["$rootScope", "$scope", "$http", function ($rootScope, $scope, $http) {
                    // DoSomething
            }])
            .controller("ControllerSecondario", ["$rootScope", "$scope", "$compile", "$http", "$window", "$timeout", "$filter", "$sce", function ($rootScope, $scope, $compile, $http, $window, $timeout, $filter, $sce) {
                //DoSomething
            });
    };
    })(NostroNameSpace || (NostroNameSpace = {})); // Se NostroNameSpace non è già stato istanziato, viene qui inizializzato ad un oggetto vuoto, altrimenti sarebbe <em>undefined</em>
    
  1. Richiamiamo l’unica funzione NostroNameSpace.Init così: angular.element(document).ready(NostroNameSpace.Init); // Di nuovo usiamo il document ready

Cosa cambia?

In Jasmine, a questo punto, faremo così:

NostroNameSpace.Init();

angular(“ModuloPerCostanti”) // Cercherà e caricherà il modulo ModuloPerCostanti

angular(“ModuloPrincipale”) // Cercherà e caricherà il modulo ModuloPrincipale

Il codice è stato rifattorizzato in maniera molto semplice, ma in questo modo possiamo testare tutto (circa 5/10 minuti di refactor, più che altro per stare attenti a non introdurre errori).

Share Button
 
W

msb4126 and OrchardCms

If you got here, probably you have just tried to build OrchardCms and got this error:
The specified solution configuration “Debug|MCD” is invalid
Maybe your laptop is an HP? It happens that on HP Laptops the Environment variable Platform is set to MCD
The solution is very easy, indeed… just go to System Properties -> Advance System Configuration -> Environment Variables and then change the value to Any CPU

variabili ambiente

Done! You can now build OrchardCms with “Build precompiled” from Visual Studio command prompt
Solution found here

Share Button
 
W

Unable to determine application identity of the caller

I’ve just got this exception in App.xaml, just at the bootstrapper line:

<Application
 x:Class="MyNamespace.App"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
 xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
 xmlns:caliburnMicro="clr-namespace:MyNamespace.CaliburnExt">

 <!--Application Resources-->
 <Application.Resources>
     <local:LocalizedStrings xmlns:local="clr-namespace:MyNamespace" 
x:Key="LocalizedStrings"/> <caliburnMicro:Bootstrapper x:Key="bootstrapper" /> </Application.Resources> </Application>

 

After a few investigation, I found out the problem was in the botstrapper, and precisely here:

protected override void Configure()
{
     container = new PhoneContainer();

     if (!Execute.InDesignMode)
     {          
          container.RegisterPhoneServices(RootFrame);
     }     
Problem is here!!!!
     container.Instance<IMobileServiceClient>(new MobileServiceClient(
                   "https://myMobileervice.azure-mobile.net/",
                   "xxxxxxxxxxxxxxxx"));            
            AddCustomConventions();            
}

To fix the issue is sufficient to move the Mobile Service registration inside “if (!Execute.InDesignMode)”

The working code is the following:

protected override void Configure()
{
     container = new PhoneContainer();

     if (!Execute.InDesignMode)
     {          
        container.RegisterPhoneServices(RootFrame);
        container.Instance<IMobileServiceClient>(
new MobileServiceClient( "https://myMobileervice.azure-mobile.net/", "xxxxxxxxxxxxxxxx")); } AddCustomConventions(); }

 

Share Button
Tagged with:  
W

App Si No Forse in certificazione – Update: nello Store

in App Win 8, IT e dintorni , by LoreX75

20121126-011235.jpg

Questa app é davvero divertente… Anche se l’ho sviluppata io, non posso non cedere alle risate ^_^
É contagioso, provare pre credere… Mentre la sviluppavo anche i miei amici non resistevano all’idea di fare una domanda e sapere il responso dell’oracolo 😉
Se volete contribuire, potete commentare qui sotto suggerendo altre risposte divertenti.
Nata come un giochino, man mano che procedevo con lo sviluppo mi sono parecchio divertito e immaginato le future versioni…. Scaricatela e vi divertirete.
Appena disponibile posterò il link qui sotto.
Potete scaricare l’App premendo qui
Nel frattempo guardate cosa pensa di se stessa, questa App 😉
20121126-013529.jpg

Share Button
Tagged with:  
W

App TechnoInfo – Update: nello store

in App Win 8, IT e dintorni , by LoreX75

20121126-010216.jpg
Questa App é un aggregatore di feed rss dei maggiori siti italiani che si occupano del pianeta informatico
Appena sarà disponibile nello store posterò il link diretto qui sotto
Potete scaricarla premendo qui.

Share Button
Tagged with:  
W

App Windows 8

in App Win 8, Io, IT e dintorni , by LoreX75

Ed ecco che sono quasi pronto alla pubblicazione della prima App sul Marketplace di Windows 8…
Appena pronta e pubblicata, seguiranno altre informazioni ^_^

Share Button
Tagged with:  
W

Io amo Spring, Io amo Spring

in IT e dintorni , by LoreX75

Ma la configurazione è un vero bagno di sangue. Ma continuo ad amarlo 😛

Share Button
 
W

Coolite e Visual Studio 2008

in Io, IT e dintorni , by LoreX75

Dopo tante ore perse a cercare, ho finalmente trovato la risposta alle mie domande.

Non capivo il perchè, inserendo in un mio file JavaScript in Visual Studio 2008 i reference a Coolite, questo mi andasse in “panico”, restituendo l’errore:

Avviso 1 Errore durante l’aggiornamento di JScript IntelliSense: Coolite.Ext.Web.Build.Resources.Coolite.extjs.adapter.ext.ext-base.js:Coolite.Ext.Web: Proprietà o metodo non supportati dall’oggetto @ 0:15649 C:\GasGis\gasgis\GasGis.GUI\OpenLayers\GespScaleControl.js 1 1 GasGis.GUI

Errore durante l’aggiornamento di JScript IntelliSense: Coolite.Ext.Web.Build.Resources.Coolite.extjs.adapter.ext.ext-base.js:Coolite.Ext.Web: Proprietà o metodo non supportati dall’oggetto @ 0:15649

Cercando sono finalmente arrivato al Bug di Visual Studio riportato in questa pagina, dove viene anche riportato il workaraound per risolvere il problema:
Visual Studio Workaround

In parole povere, per ottenere l’Intellisense funzionante con Coolite e Visual Studio 2008 basta seguire questi passi:

  1. Creare nel progetto un file javascript da includere SEMPRE come primo file in ogni altro file Javascript che referenzi Coolite. Personalmente ho chiamato questo file “Vs_WorkAround.js” ed ho inserito questa linea:
    window.addEventListener = false;
  2. Cercare nella directory di installazione di Coolite il file “intellisense.js” e copiarlo nel progetto.
    Nel mio caso tale file si trova in questa posizione”C:\Programmi\Coolite\Coolite Toolkit Community v0.8.0\Coolite – drag me into your Project [not required]\coolite\intellisense.js”
  3. Creare i file JavaScript con questa intestazione:
    ///
    ///

Spero possa essere utile ad altri senza girare come matti per la rete.

Share Button
 
W

MS & IE

in IT e dintorni , by LoreX75

Allora, siamo alle solite… La Comunità Europea ancora contro Microsoft perchè, dice, abusa della sua posizione dominante in fatto di SO per spingere il proprio Browser IE.

Per prima cosa mi dico: con tutte le urgenze economiche e sociali (diritti omosessuali, leggi abnormi sul fine vita, per esempio) che ci sono, siamo ancora qui a pensare alla guerra dei browser… vabbè, meno male che siamo in Europa, che figata!

Ho appena fatto un commento ad un articolo del Corriere della Sera, che ho deciso di riportare in toto qui:

Leggo sempre tante castronerie, purtroppo.
1) WindowsUpdate funziona solo con IE e ActiveX, questo è vero, ma nessuno ti obbliga ad usarlo, anzi: vai sul sito di MS e ti scarichi a mano le patch, tutte disponibili… se vuoi la comodità di WinUpdate usi IE, ma appunto nessuno ti obbliga
2) Uso anche Ubuntu e guarda caso quando lo installo mi ritrovo sempre FireFox…
3) Se non ci fosse alcun browser in Win, mi dite con cosa scaricate qualsiasi altro browser con il sistema appena installato? Ah,si, me lo scarica un amico o me lo prendo in una rivista e GG… io non ho problemi, ma mia madre, mio fratello, mio zio, etc dovrebbe chiedere a me; abbiate pietà!!!
4) Nonostante tutto quanto detto sopra il mio browser per eccellenza resta, al momento, FireFox (dal quale sto scrivendo)
5) Vista non usa WinUpdate da IE, ma è uno strumento a se stante, basta aggiornare il SO ad una versione più recente e non ostinarsi ad usare XP, un SO di più di 7 anni fa
6) Google parla di posizione dominante? No, scusate, parliamo del motore di ricerca che tutti, e dico tutti, usano? (io per primo, funziona meglio di tutti gli altri, cosa che non posso dire di IE, tant’è che non lo uso)
7) C’è qualche folle che chiede che MS proponga in fase di install quale browser installare? No, dico, ma siamo impazziti? Domani compro una Punto e ci trovo la pubblicità della Megane?

Detto questo, come sempre, un utente che non sia a zero in quanto ad informatizzazione si sceglie il browser che vuole, per gli altri invece, purtroppo, non saprebbero da che parte iniziare per trovarne uno se non lo trovassero già in Windows

Buona navigazione con… Firefox 🙂

Share Button