Angular JS – UI-Router – Dynamic Routing

‘use strict’;

var templateCache = {};
var controllerCache = {};

angular.module(‘interceptcms’).config(function($urlRouterProvider, $stateProvider, $httpProvider, RESOURCES) {

//$httpProvider.defaults.cache = true;

var url404 = "404";

// PASCAL CASE IS THE PREFERRED ANGULAR NAMING CONVENTION 
// FOR CONTROLLERS
function capitalizeFirstletter(string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
}

function getUrl(url) {
    var http = new XMLHttpRequest();
    http.open("GET", url, false);
    http.send();
    if (http.status === 404) {
        return;
    }
    return http.response;
}

// EVERYTHING IS GOING TO a single controller
// ANGULAR DIRECTIVES are being called dynamically via the view
// defaultCtrl.js performs generic data to api actions
function checkControllerCache() {
    var model = window.location.hash.split('/')[1] || 'default';
    if (model.indexOf('?') > -1) {
        model = model.split('?')[0];
    }
    var modelRef = capitalizeFirstletter(model) + "Ctrl";

    var ctrl = getControllerCache(model);

    if (ctrl) {
        //console.log("returning cached Controller " + ctrl);
    } else {
        var partial = model + "/" + model + ".js";
        if (getUrl(RESOURCES.COMPONENTS + partial) || getUrl(RESOURCES.CONTROLLERS + partial)) {
            setControllerCache(model, modelRef);
        } else {
            setControllerCache(model, 'DefaultCtrl');
            ctrl = 'DefaultCtrl';
        }
    }
    return ctrl;
}

function setControllerCache(ctlrRef, ctrl) {
    controllerCache[ctlrRef] = ctrl;
}

function getControllerCache(ctlrRef) {
    return controllerCache[ctlrRef];
}

// TEMPLATE CACHE
function setTemplateCache(templateName, view) {
    templateCache[templateName] = view;
}

function getTemplateCache(templateName) {
    return templateCache[templateName];
}

function checkTemplateCache(model, template) {

    var tmpl = getTemplateCache(model + template);
    var url;

    // RETURNS CACHED TEMPLATE
    if (tmpl) {
        console.log("returning cached view " + model + ":" + template);
    } else {
        url = RESOURCES.COMPONENTS + model + "/" + template + RESOURCES.VIEW_EXT;
        // RETURNS CUSTOM TEMPLATE
        tmpl = getUrl(url);

        // RETURNS DEFAULT TEMPLATE
        if (!tmpl) {
            url = RESOURCES.VIEWS + RESOURCES.DEFAULTS + "/" + template + RESOURCES.VIEW_EXT;
            tmpl = getUrl(url);
        }

        // RETURNS 404
        if (!tmpl) {
            tmpl = getUrl(RESOURCES.VIEWS + url404 + RESOURCES.VIEW_EXT);
        }
        setTemplateCache(model+template, tmpl);
    }
    return tmpl;
}

// DEFAULT ROUTE
$urlRouterProvider.otherwise('/');

// EXPLICITLY SET ROUTES
// GENERIC APP FUNCTIONALITY

$stateProvider
.state('main', {
    url: '/',
    templateUrl: RESOURCES.VIEWS + 'main' + RESOURCES.VIEW_EXT
})

.state('register', {
    url: '/register',
    templateUrl: RESOURCES.VIEWS + 'register' + RESOURCES.VIEW_EXT,
    controller: 'RegisterCtrl'

})

.state('login', {
    url: '/login',
    templateUrl: RESOURCES.VIEWS + 'login' + RESOURCES.VIEW_EXT,
    controller: 'LoginCtrl'
})

.state('forgot', {
    url: '/forgot',
    templateUrl: RESOURCES.VIEWS + 'forgot' + RESOURCES.VIEW_EXT,
    controller: 'ForgotCtrl'
})

.state('reset/:id', {
    url: '/reset/:id',
    templateUrl: RESOURCES.VIEWS + 'reset' + RESOURCES.VIEW_EXT,
    controller: 'ResetCtrl'
})


.state('logout', {
    url: '/logout',
    controller: 'LogoutCtrl'
});


// DYNAMICALLY ADD STATES FROM ARRAY 
// CREATED ON PAGE LOAD
// CREATE AN ARRAY OF OBJECTS WITH STATE, CTRL and FEATURENESTING PROPERTIES
// ex: [{ state:'essay', ctrl:"EssaysCtrl", featureNesting: false }]

function createState(stateCtrl){
    var ctrl = stateCtrl.ctrl;
    var state = stateCtrl.state;
    var path = (stateCtrl.featureNesting) ? RESOURCES.COMPONENTS + "/" + state + "/" : RESOURCES.VIEWS;
    var list = {
        url: "/" + state ,
        templateUrl: path + state + "-" + RESOURCES.LIST + RESOURCES.VIEW_EXT,
        controller: ctrl
    };

    var create = {
        url: "/" + state + "/" + RESOURCES.CREATE,
        templateUrl: path + state + "-" + RESOURCES.EDIT + RESOURCES.VIEW_EXT,
        controller: ctrl    
    };

    var view = {
        url: "/" + state + "/:id",
        templateUrl: path + state + "-" + RESOURCES.VIEW + RESOURCES.VIEW_EXT,
        controller: ctrl
    };

    var edit = {
        url: "/" + state + "/:id" + RESOURCES.EDIT,
        templateUrl: path + state + "-" + RESOURCES.EDIT + RESOURCES.VIEW_EXT,
        controller: ctrl
    };

    $stateProvider.state(state, list);
    $stateProvider.state(state + "/" + RESOURCES.CREATE, create);
    $stateProvider.state(state + "/", view);
    $stateProvider.state(state + "/" + RESOURCES.EDIT + "/", edit);
}

// ADD NEW STATES IN FOR EACH LOOP
angular.forEach(RESOURCES.STATECTRLS, function (stateCtrl) {
    createState(stateCtrl);
});

// FULL DYNAMIC ROUTING
// CHECKS FOR CUSTOM CONTROLLER NESTED IN COMPONENTS
// CHECKS FOR CUSTOM CONTROLLER IN CONTROLLERS
// FAILS TO GENERIC DEFAULT CONTROLLER
// CHECKS FOR CUSTOM VIEWS NESTED IN COMPONENTS
// FAILS TO GENERIC VIEWS

$stateProvider

// EDIT RECORD
.state('/:model/:id/' + RESOURCES.EDIT, {
    url: '/:model/:id/' + RESOURCES.EDIT,
    template: function(stateParams) {
        return checkTemplateCache(stateParams.model, RESOURCES.EDIT);
    },
    controller: checkControllerCache()
})

// CREATE RECORD
.state('/:model/' + RESOURCES.CREATE, {
    url: '/:model/' + RESOURCES.CREATE,
    template: function(stateParams) {
        return checkTemplateCache(stateParams.model, RESOURCES.EDIT);
    },
    controller: checkControllerCache()
})

// LIST VIEW
.state('/:model/' + RESOURCES.LIST, {
    url: '/:model/' + RESOURCES.LIST,
    template: function(stateParams) {
        return checkTemplateCache(stateParams.model, RESOURCES.LIST);
    },
    controller: checkControllerCache()
})

// RECORD VIEW
.state('/:model/:id', {
    url: '/:model/:id',
    template: function(stateParams) {
        return checkTemplateCache(stateParams.model, RESOURCES.VIEW);   
    },
    controller: checkControllerCache()
})

// SEARCH LIST VIEW
.state('/:model/' + RESOURCES.SEARCH + "/:search?:skip&:limit", {
    url: '/:model/' + RESOURCES.SEARCH + "/:search?:skip&:limit",
    template: function(stateParams) {
        return checkTemplateCache(stateParams.model, RESOURCES.LIST);
    },
    controller: checkControllerCache()
})

// SEARCH LIST VIEW
.state('/:model/' + RESOURCES.SEARCH + "/:search", {
    url: '/:model/' + RESOURCES.SEARCH + "/:search",
    template: function(stateParams) {
        return checkTemplateCache(stateParams.model, RESOURCES.LIST);
    },
    controller: checkControllerCache()
})

// ADDITIONAL LIST VIEW
.state('/:model/' + RESOURCES.LIST + '/:page', {
    url: '/:model/' + RESOURCES.LIST + '/:page',
    template: function(stateParams) {
        return checkTemplateCache(stateParams.model, stateParams.page);
    },
    controller: checkControllerCache()
})

// ADDITIONAL ITEM VIEW
.state('/:model/:id/:page', {
    url: '/:model/:id/:page',
    template: function(stateParams) {
        return checkTemplateCache(stateParams.model, stateParams.page); 
    },
    controller: checkControllerCache()
})

// DEFAULT LIST VIEW
.state('/:model?skip:skip&limit:limit', {
    url: '/:model?:skip&:limit',
    template: function(stateParams) {
        return checkTemplateCache(stateParams.model, RESOURCES.LIST);   
    },
    controller: checkControllerCache()
})

.state('/:model', {
    url: '/:model',
    template: function(stateParams) {
        return checkTemplateCache(stateParams.model, RESOURCES.LIST);   
    },
    controller: checkControllerCache()
});

$httpProvider.interceptors.push('authInterceptor');

});

Leave a Reply

Your email address will not be published. Required fields are marked *