viernes, 5 de septiembre de 2014

Compatibilidad angularJS con Windows 8.1 Store App.

A continuación os mostraré algunos problemas que van saliendo al desarrollar una aplicación de Windows 8.1 Store o Windows Phone 8.1 en AngularJS.
  • Al cargar la aplicación Angular, recibimos una excepción que indica que se está manipulando el documento de forma no segura (angular internamente usa JQuery).

    Error en tiempo de ejecución de JavaScript: No se puede agregar contenido dinámico. Un script intentó inyectar contenido dinámico, o elementos anteriormente modificados dinámicamente, que probablemente no sea seguro. Por ejemplo, el uso de la propiedad innerHTML para agregar un script o HTML con un formato incorrecto generará esta excepción. Recurra al método toStaticHTML para filtrar el contenido dinámico o cree elementos y atributos expresamente con un método como createElement. Para obtener más información, consulte http://go.microsoft.com/fwlink/?LinkID=247104.

    WinJS proporciona métodos para ejecutar código que manipula el DOM de forma segura, es decir funciones donde podemos usar JQuery y no se generaría la excepción… pero usando WinJS nuestra aplicación ya no sería compatible en otras plataformas y seguramente tendríamos que modificar el core module de Angular lo cual es un engorro y si queremos mantenernos actualizados con bower se perderían estos cambios. Os paso una alternativa, que altera algunos aspectos del comportamiento javascript de la aplicación que lo harán compatible con Windows sin necesidad de WinJS, se trata de descargar el .js y referenciarlo antes que inicie Angular.
    https://github.com/MsopenTech/winstore-jscompat
    
  • Otro problema es que los links del menú en Windows Store no funcionaba, al hacer click en algún elemento mostraba el siguiente mensaje:

    No Apps are installed to open this type of link (unsafe)

    Se soluciona añadiendo el siguiente fragmento de código después de iniciar AngularJs (app).
    //AngularJS
        var app = angular.module('app', [
             //Angular modules 
             'cmApp',
             'cmLayout'
        ]); 
    
    //solventa problema con los links del menú en Windows8
        app.config(['$compileProvider', function ($compileProvider) {
            $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|file|ms-appx):/);
        }]);
    
  • El siguiente problema, lo he detectado en el botón de atrás que incorporo en el layout (se muestra en todas las vistas que lo necesitan). Yo estaba retrocediendo a la vista anterior con {windows.history.back();} (sí…. no me había roto los cuernos XD, pero funcionaba en Android y Web). Esto no funciona en la aplicación Windows 8.1, no hace nada al pulsar el botón. Decido controlar el tema desde Angular, podemos capturar el evento routeChangeStart y crearnos un Array donde ir almacenando las páginas por las que navegamos. Lo creo en el contexto del controlador de layout. Back() de este modo será accesible para todos los contextos que se vayan cargando a medida que el usuario navega. Seguramente hayan alternativas más elaboradas (…) pero aquí os dejo esta solución por si ayuda. (a partir de la línea $scope.history =…)
    (function () {
        "use strict";
        var layout = angular.module('cmLayout');
        layout.controller('layoutController', ['$scope', '$location','$route','menu', function ($scope,$location, $route,menu) {
            $scope.isLatMenuVisible = (menu.type === 1);
            $scope.isTopMenuVisible = (menu.type === 0);
            $scope.listItemsOnRow = 1;
            $scope.setListItemsOnRow = function (value) {
                $scope.listItemsOnRow = value;
            };
    
            $scope.history = [];
            $scope.$on('$routeChangeStart', function (event, route) {
                event.preventDefault();
                if (route.$$route)
                    $scope.history.push(route.$$route.originalPath);
            });
            $scope.Back = Back;
            function Back() {
                var item = $scope.history.length - 2;
                if (item >= 0) {
                    $location.path($scope.history[item]);
                }
            }
        }]);
    }());
    
    Y en la vista:
    <button type="button" class="btn btn-default" ng-click="Back()">
    
Hasta aquí el artículo de hoy, hasta la próxima. No olvides consultar el archivo de areaTIC tal vez haya algún tema que pueda interesarte!