{"id":238,"date":"2015-04-20T22:39:20","date_gmt":"2015-04-20T22:39:20","guid":{"rendered":"https:\/\/www.tech.shinynewthings.com\/?p=238"},"modified":"2015-04-20T22:39:20","modified_gmt":"2015-04-20T22:39:20","slug":"angular-js-ui-router-dynamic-routing","status":"publish","type":"post","link":"https:\/\/www.tech.shinynewthings.com\/?p=238","title":{"rendered":"Angular JS &#8211; UI-Router  &#8211; Dynamic Routing"},"content":{"rendered":"<p>&#8216;use strict&#8217;;<\/p>\n<p>var templateCache = {};<br \/>\nvar controllerCache = {};<\/p>\n<p>angular.module(&#8216;interceptcms&#8217;).config(function($urlRouterProvider, $stateProvider, $httpProvider, RESOURCES) {<\/p>\n<pre><code>\/\/$httpProvider.defaults.cache = true;\n\nvar url404 = \"404\";\n\n\/\/ PASCAL CASE IS THE PREFERRED ANGULAR NAMING CONVENTION \n\/\/ FOR CONTROLLERS\nfunction capitalizeFirstletter(string) {\n    return string.charAt(0).toUpperCase() + string.slice(1);\n}\n\nfunction getUrl(url) {\n    var http = new XMLHttpRequest();\n    http.open(\"GET\", url, false);\n    http.send();\n    if (http.status === 404) {\n        return;\n    }\n    return http.response;\n}\n\n\/\/ EVERYTHING IS GOING TO a single controller\n\/\/ ANGULAR DIRECTIVES are being called dynamically via the view\n\/\/ defaultCtrl.js performs generic data to api actions\nfunction checkControllerCache() {\n    var model = window.location.hash.split('\/')[1] || 'default';\n    if (model.indexOf('?') &gt; -1) {\n        model = model.split('?')[0];\n    }\n    var modelRef = capitalizeFirstletter(model) + \"Ctrl\";\n\n    var ctrl = getControllerCache(model);\n\n    if (ctrl) {\n        \/\/console.log(\"returning cached Controller \" + ctrl);\n    } else {\n        var partial = model + \"\/\" + model + \".js\";\n        if (getUrl(RESOURCES.COMPONENTS + partial) || getUrl(RESOURCES.CONTROLLERS + partial)) {\n            setControllerCache(model, modelRef);\n        } else {\n            setControllerCache(model, 'DefaultCtrl');\n            ctrl = 'DefaultCtrl';\n        }\n    }\n    return ctrl;\n}\n\nfunction setControllerCache(ctlrRef, ctrl) {\n    controllerCache[ctlrRef] = ctrl;\n}\n\nfunction getControllerCache(ctlrRef) {\n    return controllerCache[ctlrRef];\n}\n\n\/\/ TEMPLATE CACHE\nfunction setTemplateCache(templateName, view) {\n    templateCache[templateName] = view;\n}\n\nfunction getTemplateCache(templateName) {\n    return templateCache[templateName];\n}\n\nfunction checkTemplateCache(model, template) {\n\n    var tmpl = getTemplateCache(model + template);\n    var url;\n\n    \/\/ RETURNS CACHED TEMPLATE\n    if (tmpl) {\n        console.log(\"returning cached view \" + model + \":\" + template);\n    } else {\n        url = RESOURCES.COMPONENTS + model + \"\/\" + template + RESOURCES.VIEW_EXT;\n        \/\/ RETURNS CUSTOM TEMPLATE\n        tmpl = getUrl(url);\n\n        \/\/ RETURNS DEFAULT TEMPLATE\n        if (!tmpl) {\n            url = RESOURCES.VIEWS + RESOURCES.DEFAULTS + \"\/\" + template + RESOURCES.VIEW_EXT;\n            tmpl = getUrl(url);\n        }\n\n        \/\/ RETURNS 404\n        if (!tmpl) {\n            tmpl = getUrl(RESOURCES.VIEWS + url404 + RESOURCES.VIEW_EXT);\n        }\n        setTemplateCache(model+template, tmpl);\n    }\n    return tmpl;\n}\n\n\/\/ DEFAULT ROUTE\n$urlRouterProvider.otherwise('\/');\n\n\/\/ EXPLICITLY SET ROUTES\n\/\/ GENERIC APP FUNCTIONALITY\n\n$stateProvider\n.state('main', {\n    url: '\/',\n    templateUrl: RESOURCES.VIEWS + 'main' + RESOURCES.VIEW_EXT\n})\n\n.state('register', {\n    url: '\/register',\n    templateUrl: RESOURCES.VIEWS + 'register' + RESOURCES.VIEW_EXT,\n    controller: 'RegisterCtrl'\n\n})\n\n.state('login', {\n    url: '\/login',\n    templateUrl: RESOURCES.VIEWS + 'login' + RESOURCES.VIEW_EXT,\n    controller: 'LoginCtrl'\n})\n\n.state('forgot', {\n    url: '\/forgot',\n    templateUrl: RESOURCES.VIEWS + 'forgot' + RESOURCES.VIEW_EXT,\n    controller: 'ForgotCtrl'\n})\n\n.state('reset\/:id', {\n    url: '\/reset\/:id',\n    templateUrl: RESOURCES.VIEWS + 'reset' + RESOURCES.VIEW_EXT,\n    controller: 'ResetCtrl'\n})\n\n\n.state('logout', {\n    url: '\/logout',\n    controller: 'LogoutCtrl'\n});\n\n\n\/\/ DYNAMICALLY ADD STATES FROM ARRAY \n\/\/ CREATED ON PAGE LOAD\n\/\/ CREATE AN ARRAY OF OBJECTS WITH STATE, CTRL and FEATURENESTING PROPERTIES\n\/\/ ex: [{ state:'essay', ctrl:\"EssaysCtrl\", featureNesting: false }]\n\nfunction createState(stateCtrl){\n    var ctrl = stateCtrl.ctrl;\n    var state = stateCtrl.state;\n    var path = (stateCtrl.featureNesting) ? RESOURCES.COMPONENTS + \"\/\" + state + \"\/\" : RESOURCES.VIEWS;\n    var list = {\n        url: \"\/\" + state ,\n        templateUrl: path + state + \"-\" + RESOURCES.LIST + RESOURCES.VIEW_EXT,\n        controller: ctrl\n    };\n\n    var create = {\n        url: \"\/\" + state + \"\/\" + RESOURCES.CREATE,\n        templateUrl: path + state + \"-\" + RESOURCES.EDIT + RESOURCES.VIEW_EXT,\n        controller: ctrl    \n    };\n\n    var view = {\n        url: \"\/\" + state + \"\/:id\",\n        templateUrl: path + state + \"-\" + RESOURCES.VIEW + RESOURCES.VIEW_EXT,\n        controller: ctrl\n    };\n\n    var edit = {\n        url: \"\/\" + state + \"\/:id\" + RESOURCES.EDIT,\n        templateUrl: path + state + \"-\" + RESOURCES.EDIT + RESOURCES.VIEW_EXT,\n        controller: ctrl\n    };\n\n    $stateProvider.state(state, list);\n    $stateProvider.state(state + \"\/\" + RESOURCES.CREATE, create);\n    $stateProvider.state(state + \"\/\", view);\n    $stateProvider.state(state + \"\/\" + RESOURCES.EDIT + \"\/\", edit);\n}\n\n\/\/ ADD NEW STATES IN FOR EACH LOOP\nangular.forEach(RESOURCES.STATECTRLS, function (stateCtrl) {\n    createState(stateCtrl);\n});\n<\/code><\/pre>\n<p>\/\/ FULL DYNAMIC ROUTING<br \/>\n \/\/     CHECKS FOR CUSTOM CONTROLLER NESTED IN COMPONENTS<br \/>\n \/\/     CHECKS FOR CUSTOM CONTROLLER IN CONTROLLERS<br \/>\n \/\/     FAILS TO GENERIC DEFAULT CONTROLLER<br \/>\n \/\/     CHECKS FOR CUSTOM VIEWS NESTED IN COMPONENTS<br \/>\n \/\/     FAILS TO GENERIC VIEWS<\/p>\n<pre><code>$stateProvider\n\n\/\/ EDIT RECORD\n.state('\/:model\/:id\/' + RESOURCES.EDIT, {\n    url: '\/:model\/:id\/' + RESOURCES.EDIT,\n    template: function(stateParams) {\n        return checkTemplateCache(stateParams.model, RESOURCES.EDIT);\n    },\n    controller: checkControllerCache()\n})\n\n\/\/ CREATE RECORD\n.state('\/:model\/' + RESOURCES.CREATE, {\n    url: '\/:model\/' + RESOURCES.CREATE,\n    template: function(stateParams) {\n        return checkTemplateCache(stateParams.model, RESOURCES.EDIT);\n    },\n    controller: checkControllerCache()\n})\n\n\/\/ LIST VIEW\n.state('\/:model\/' + RESOURCES.LIST, {\n    url: '\/:model\/' + RESOURCES.LIST,\n    template: function(stateParams) {\n        return checkTemplateCache(stateParams.model, RESOURCES.LIST);\n    },\n    controller: checkControllerCache()\n})\n\n\/\/ RECORD VIEW\n.state('\/:model\/:id', {\n    url: '\/:model\/:id',\n    template: function(stateParams) {\n        return checkTemplateCache(stateParams.model, RESOURCES.VIEW);   \n    },\n    controller: checkControllerCache()\n})\n\n\/\/ SEARCH LIST VIEW\n.state('\/:model\/' + RESOURCES.SEARCH + \"\/:search?:skip&amp;:limit\", {\n    url: '\/:model\/' + RESOURCES.SEARCH + \"\/:search?:skip&amp;:limit\",\n    template: function(stateParams) {\n        return checkTemplateCache(stateParams.model, RESOURCES.LIST);\n    },\n    controller: checkControllerCache()\n})\n\n\/\/ SEARCH LIST VIEW\n.state('\/:model\/' + RESOURCES.SEARCH + \"\/:search\", {\n    url: '\/:model\/' + RESOURCES.SEARCH + \"\/:search\",\n    template: function(stateParams) {\n        return checkTemplateCache(stateParams.model, RESOURCES.LIST);\n    },\n    controller: checkControllerCache()\n})\n\n\/\/ ADDITIONAL LIST VIEW\n.state('\/:model\/' + RESOURCES.LIST + '\/:page', {\n    url: '\/:model\/' + RESOURCES.LIST + '\/:page',\n    template: function(stateParams) {\n        return checkTemplateCache(stateParams.model, stateParams.page);\n    },\n    controller: checkControllerCache()\n})\n\n\/\/ ADDITIONAL ITEM VIEW\n.state('\/:model\/:id\/:page', {\n    url: '\/:model\/:id\/:page',\n    template: function(stateParams) {\n        return checkTemplateCache(stateParams.model, stateParams.page); \n    },\n    controller: checkControllerCache()\n})\n\n\/\/ DEFAULT LIST VIEW\n.state('\/:model?skip:skip&amp;limit:limit', {\n    url: '\/:model?:skip&amp;:limit',\n    template: function(stateParams) {\n        return checkTemplateCache(stateParams.model, RESOURCES.LIST);   \n    },\n    controller: checkControllerCache()\n})\n\n.state('\/:model', {\n    url: '\/:model',\n    template: function(stateParams) {\n        return checkTemplateCache(stateParams.model, RESOURCES.LIST);   \n    },\n    controller: checkControllerCache()\n});\n\n$httpProvider.interceptors.push('authInterceptor');\n<\/code><\/pre>\n<p>});<\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#8216;use strict&#8217;; var templateCache = {}; var controllerCache = {}; angular.module(&#8216;interceptcms&#8217;).config(function($urlRouterProvider, $stateProvider, $httpProvider, RESOURCES) { \/\/$httpProvider.defaults.cache = true; var url404 = &#8220;404&#8221;; \/\/ 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(&#8220;GET&#8221;, url, false); http.send(); if [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-238","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.tech.shinynewthings.com\/index.php?rest_route=\/wp\/v2\/posts\/238","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tech.shinynewthings.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tech.shinynewthings.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tech.shinynewthings.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tech.shinynewthings.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=238"}],"version-history":[{"count":1,"href":"https:\/\/www.tech.shinynewthings.com\/index.php?rest_route=\/wp\/v2\/posts\/238\/revisions"}],"predecessor-version":[{"id":239,"href":"https:\/\/www.tech.shinynewthings.com\/index.php?rest_route=\/wp\/v2\/posts\/238\/revisions\/239"}],"wp:attachment":[{"href":"https:\/\/www.tech.shinynewthings.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=238"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tech.shinynewthings.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=238"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tech.shinynewthings.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=238"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}