Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have a walkthrough in my app which comprises 4 pages. I decided to make the Walkthrough a single state with multiple views to represent each of the 4 pages.

In my html I define a div as a ui-view pointed to the current view, which my controller then changes around as necessary.

The problem is, when I update $scope.currentView to 'general' it does not change what's actually seen on the screen! If I manually change it to 'general' in my _init function it does show the general page, but I cannot make it change based on a button click.

HTML:

<div ui-view="{{currentView}}@walkthrough"></div>

Controller:

var _init = function () {
    $scope.currentView = 'welcome';
};
_init();

$scope.setView = function (view) {
    $scope.currentView = view;
};

My state definition:

.state('walkthrough', {
    url: '/walkthrough',
    views: {
        '': {
            templateUrl: 'app/walkthrough/walkthrough.html',
            controller: 'walkthroughController'
        },
        'welcome@walkthrough': {
            templateUrl: 'app/walkthrough/welcome.html'
        },
        'general@walkthrough': {
            template: 'general'
        }
    }
})

And the button to update the view:

<img class="start-button center-block" ng-click="setView('general')" />

Update 1

I have tried the following to solve, none of which worked:

  1. Changing currentView to a getter function getCurrentView() which returns the currentView. Same behavior.
  2. Wrapping the currentView setter in a $scope.$apply. Get the $apply already in progress error
  3. Wrapping the currentView setter in a $timeout. Same behavior

Update 2

I added a <pre> section which calls the identical code as in the ui-view, {{currentView}}@walkthrough. It shows the correct view, even though the page itself doesn't update the show the new view.

Update 3

I have tried every combination of how to programmatically set the view but nothing I've tried has worked. Whether I use a server to grab the view, function, straight up $scope variable, nothing. The variable itself is correct, but the view just won't change when I change the variable.

The strange part is it works once when I set the value of the currentView in my init() function. It works if I change the value to one of the next views in the code itself ($scope.currentView = 'general' <- this shows the general page), but not if I make a button click change the currentView to 'general'.

I've tried all manner of $scope.$applys, $digests, and $timeouts. Nothing I do will get the view itself to update. The only thing left is to make it into a bunch of divs with ng-show/hide which is really ugly and a pain to manage, and the reason I wanted to use views in the first place.

Update 4

Still no progress, regardless of what I try... I thought some weird combination of wrapping the variable change in a $timeout might prove useful but alas, nothing. My last thought was to change all of these to their own independent states, but then I'll end up with a bunch of duplicated code which is obviously not good. I use almost the same type of change in other section of my app (to change states though, not views), and it works perfectly. I cannot figure out why I can't change the view dynamically. Any help would be greatly appreciated.

Update 5

Had some home after user's comment below but it has lead nowhere. I have tried to call all manner of $state changes to refresh the view but nothing has worked. I tried all of the follow, none of which had any impact on the page:

$state.reload();
$state.go($state.current, {}, { reload: true });
$state.transitionTo($state.current, $stateParams, {
    reload: true,
    inherit: false,
    notify: true
});
share|improve this question
    
Can you post the code for how the view ID is being passed to setView on click? –  Aweary Mar 1 at 17:31
    
@Aweary <img class="start-button center-block" ng-click="setView('general')" /> –  Joshua Ohana Mar 1 at 17:32
    
@Aweary I trued using ng-click="currentView='general'" but that doesn't change the view at all (even when looking at debug vals) –  Joshua Ohana Mar 1 at 17:41

2 Answers 2

up vote 0 down vote accepted

So I solved this by just making every walkthrough page its own inherited state from parent walkthrough, each with the single view. Probably not the best method but I don't want to waste more time on this.

I would still love a method to just use nested views and navigate that way, since it'll be easier to add more in the future with that method without bloating my stateProvider.

        .state('walkthrough', {
            url: '/walkthrough',
            views: {
                '': {
                    templateUrl: 'app/walkthrough/walkthrough.html',
                    controller: 'walkthroughController'
                }
            }
        })
        .state('walkthrough.welcome', {
            url: '/welcome',
            views: {
                'walkthrough.welcome@walkthrough': {
                    templateUrl: 'app/walkthrough/welcome.html'
                }
            }
        })
        .state('walkthrough.general', {
            url: '/general',
            views: {
                'walkthrough.general@walkthrough': {
                    templateUrl: 'app/walkthrough/general.html'
                }
            }
        })
        .state('walkthrough.business', {
            url: '/business',
            views: {
                'walkthrough.business@walkthrough': {
                    templateUrl: 'app/walkthrough/business.html'
                }
            }
        })
        .state('walkthrough.friends', {
            url: '/friends',
            views: {
                'walkthrough.friends@walkthrough': {
                    templateUrl: 'app/walkthrough/friends.html'
                }
            }
        })

Now I can easily navigate between by using

<img ui-sref="walkthrough.general" />
share|improve this answer

While the ui-view directive will take an interpolated value ({{ something }}) for the view name, it doesn't actually watch this for changes. Instead, view updates are only triggered by the $stateChangeSuccess and $viewContentLoading events. This is why you can observe it working the first time and only the first time.

You can verify this by looking at the linking function for the $ViewDirective in ui-router's source code: https://github.com/angular-ui/ui-router/blob/master/src/viewDirective.js.

This means that your setView function needs to call $state.goto trigger a state change, rather than just setting a property on scope. As pe the usual state change process, this will eventually result in a $stateChangeSuccess event being broadcast.

share|improve this answer
    
Thanks but this did not work. I am not actually changing state...only changing view. I tried to call a $state.go('walkthrough') anyway but this did not do anything, which I had expected since it was my current state anyway. –  Joshua Ohana Mar 2 at 9:59
    
that was the point - to "change the view", you must do a state change. However, if you are already in the walkthrough state and call $state.go('walkthrough'), the router won't reload the state unless you specifically tell it to (reload: true). –  user2943490 Mar 2 at 22:19
    
I had reload: true (as you can see in Update 5 in my post) but it still was not working. I ended up just reworking that whole section so now each page is it's on child state of the parent 'walkthrough', working pretty well. –  Joshua Ohana Mar 3 at 13:43

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.