1

I am using ui-router and Named views. it works flawlessly but it doesn't suit my purpose. I don't want the templates to be injected everytime i click on the menu item but only the first time it is clicked after application is loaded. The remaining times, it should simply hide the template and show the template that is currently active for a menu click. when coming back to the original menu click, it should just do ngShow="true" for the hidden template and hide the current one. Is that possible to do without editing the cleanupLastView() in the angular-ui-router?

If i comment out the cleanupLastView(), it simply keeps on injecting templates and does nothing to older templates. So both end up showing. Tried to debug the cleanupLastView() but i couldn't figure out what variables are available to me there so i could re-show what ever is clicked a second time rather than inject again.

index.html

<!DOCTYPE html> 
<html lang="en"> 
<head ng-app="myApp"> 
        <meta name="viewport" content="width=device-width, initial-scale=1"> 
    <link href="style.css" rel="stylesheet"> 
    <script type="text/javascript" src=".lib/angular-1.3.0/angular.js"></script> 
    <script type="text/javascript" src="./angular-ui-router.js"></script> 
    <script type="text/javascript" src="./modular/ct-ui-router-extras.core.js"></script> 
    <script type="text/javascript" src="./modular/ct-ui-router-extras.dsr.js"></script> 
    <script type="text/javascript" src="../timerService.js"></script> 
    <script type="text/javascript" src="../dataService.js"></script> 
    <script type="text/javascript" src="app.js"></script> 
</head> 
<body> 
<div class="navbar navbar-default navbar-static-top" role="navigation"> 
    <ul class="nav navbar-nav"> 
        <li ng-class="{active: $state.includes('main')}"><a ui-sref="home">Main</a></li> 
        <li ng-class="{active: $state.includes('files')}"><a ui-sref="files">Files</a></li> 
    </ul> 
</div> 
<div> 
    <div ui-view="pane"></div> 
</div> 
</div> 
</body> 
</html>

app.js

var myApp = angular.module("myApp", [ 'ui.router', 'ct.ui.router.extras.dsr']); 
app.config(function ($stateProvider, $urlRouterProvider) { 
    $urlRouterProvider.otherwise("/"); 
        $stateProvider
    .state('main',
    url:"/main",
             deepStateRedirect: true,
    views : {
        pane: {
            templateUrl : 'tpl.pane-0.html'
            },
        }
    )
.state('files',
    url: '/files',
             deepStateRedirect: true,
    views : {
        pane : {
            templateUrl : 'tpl.pane-1.html'
            },
        'first@files' : {
            templateUrl : 'tpl1.first.html',
                              deepStateRedirect: true
            },
        'second@files' : {
            templateUrl : 'tpl1.second.html',
                              deepStateRedirect: true
            },  
        },
    )
  });

tpl.pane-0.html

<div>
    <input type='text'></input>
</div>

tpl.pane-1.html

<div >
    <div data-ui-href='first'></div>
    <div data-ui-href='second'></div>
</div> 

tpl1.first.html

<div>
    <input type='text'></input>
</div>

tpl1.second.html

<div>
Second
</div>

This is the simplified code of my app. it works to do the multiple named views but fails at deepStateRedirect which seems to be the one associated with nav bar type of templates rather than(?) Sticky. Is that correct? I added the param deepStateRedirect: true to allthe views being injected but to no avail. if the tpl1.first.html's input text box is written and the view switched to main, and come back, there is no text to be found in the input box. What am i doing wrong?

Ram
  • 325
  • 4
  • 22

2 Answers2

1

Yes, you can do this but it requires some custom work.

  • Change the state so that it uses an empty template.
  • In the state's controller check if the document already contains the HTML for the view (use a unique ID).
  • If required, use the $template cache and $compile to create the original template view and append it to the document body.
  • In the template, you can use ng-show="isState_expression | isState" expression to toggle the visibility of the template.

Basically the ui-routes work the same as before, but you're handling the compiling of the template yourself. Once it's in the DOM (not inside the ui-view). You can just leave it there to be handled by ng-show.

I don't recommend using resolve on the state since it's going to become a static state.

Here's the manual on $compile:

https://docs.angularjs.org/api/ng/service/$compile

Here's a tutorial on $compile:

http://www.benlesh.com/2013/08/angular-compile-how-it-works-how-to-use.html

Here's a stack answer on $compile:

Compiling dynamic HTML strings from database

Community
  • 1
  • 1
Reactgular
  • 52,335
  • 19
  • 158
  • 208
  • Thanks! i tried to follow your code and see that i can create my own functions to create and hide views in the compile function rather than use the regular cleanupLastView() and updateView(boolean) methods. But access variables seems a problem. couldnt access $templateCache in there. – Ram Mar 03 '15 at 13:52
1

Why doesn't it suit your needs? Do you need to preserve the states when they are not shown?

If so, perhaps you should look into UI Router Extras Sticky States. It allows you to preserve the $scope of a state and not create/destroy it every time. This would be better than trying to reinvent the wheel.

Take a look at the sample.

gaiazov
  • 1,908
  • 14
  • 26
  • Hi, sounds like a good one. But it seems restricted to tabs. Is there a way i can make it work for any DIV element into which templates are injected? – Ram Mar 03 '15 at 13:50
  • Not at all. You can use whatever you want to use to toggle the views (states). – gaiazov Mar 03 '15 at 17:56
  • i tried the deepStateRedirect example and created code as above combining it with multiple named views. It didnt work for deepStateRedirect. I chose it because it said used for navigation type of menus in the explanantion of deepStateRedirect. Is that correct? Please let me know how i'm doing wrong. – Ram Mar 04 '15 at 19:59