Setting slide index at controller initialization?

Before moving my angular app to ionic, I had hand-hacked up a navigation somewhat like the ionic slideBox. I was displaying a series of cruise ship deck images, and the routing was such that /decks/2 would take you to deck 2, /decks/3 to 3.

I’ve switched it to using slideBox and it works very smoothly (unlike my version :P) but I have 2 things I can’t seem to make work.

  1. I’d love to update the history so that when a slide changes, the route updates like the old code.
  2. I want to be able to start on slide index n, based on the route passed in when the controller’s initialized.

Does anyone have any ideas how that would work?

For #2, I’ve tried doing something like “$scope.$broadcast(‘setSlide’, 3)”, or putting that inside a $timeout() or $scope.$evalAsync() call, but it seems the slideBox is not initialized by the time anything gets called from my end.

2 Likes

You are almost there, but your broadcast is wrong.

Here is a sample to setup your route:

        $routeProvider.when('/intro', {
            templateUrl: 'templates/intro.html',
            controller: 'IntroController',
            resolve : {
                loadData: function(AccountService) {
                    return AccountService.initialize();
                }
            }
        });

        $routeProvider.when('/intro/:slideNum', {
            templateUrl: 'templates/intro.html',
            controller: 'IntroController',
            resolve : {
                loadData: function(AccountService) {
                    return AccountService.initialize();
                }
            }
        });

That gives you the ability to append the desired slide number on the end.

Now, in your controller, you need to do this:

    .controller('IntroController', ['$scope', '$location', '$timeout', '$routeParams', function($scope, $location, $timeout, $routeParams, ) {

        if($routeParams.slideNum) {
            console.log('You want slide ' + $routeParams.slideNum);

            $timeout( function() {
                $scope.$broadcast('slideBox.setSlide', $routeParams.slideNum);
            }, 10);
        }
…
…


        // Called each time the slide changes
        $scope.slideChanged = function(index) {

            previousSlide = currentSlide;
            currentSlide = index;

            $location.path('/intro/' + index);
        }
...
….

However, this is going to look pretty ugly. Every time you change the slide, the URL is going to change, the controller is going to reload. Then, the controller will decided what slide to go to. Then, it will transition to it. I looks pretty clunky.

Also, I believe Ionic will soon switch to the Angular UI-router way of handling views. This will allow you to set state on the URL without necessarily reloading the controller. I think this could look a lot better once hi-router is rolled out.

OK, this is exactly what I was doing, only I was waiting 0 milliseconds instead of 10 just to get to the next UI update cycle. Is that a race-conditiony thing? Is there a way to actually be sure I can trigger when things are finished initializing?

Ah, excellent! I don’t need to be finished for a while, so I’ve got some time to play with. What’s the timeline for that?

Just checked out and had a look through the 0.9.19 codebase. @RangerRick , I noticed that angular ui-router is now included in the distribution.

@Calendee, do you know if the new slideBox scope attribute activeSlide was intended to replace the $scope.$broadcast method you suggest above as a way to bind the currently selected slide to a controller variable?

Edit: I guess my last question might have been better directed at @max

1 Like

Yeah, I just tried updating to the latest source and saw the ui-router commit as well. Happy to say, the ui-router stuff is working great, and I was able to use a state change without reloading the view like this:

		$scope.$on('slideBox.slideChanged', function(e, index) {
		$scope.deck = index + 2;
		updateUI();
		$state.transitionTo('deck-plans', {
			deck: $scope.deck
		}, {
			location: true,
			inherit: true,
			notify: false,
			reload: false
		});
	});

Can’t say if I’m supposed to be using properties directly, but it works. Thanks for the pointers.

1 Like

Looks to be the base. Here is the PR for it : https://github.com/driftyco/ionic/pull/379

So, you would set it initially and then based on actions, you can change it on the fly.

I’m trying to convert to the new release to test it. I will let you know if I work it out.

There is one problem with the active-slide setting. When the slideBox is loaded, it is ignored due to a bug. So, on initial setup, the desired slide will not be loaded. It will default to slide 0.

I’ve put in a PR that fixes this : https://github.com/driftyco/ionic/pull/398

Correction : The PR is now : https://github.com/driftyco/ionic/pull/400

I also noticed that the watch that was registered on the the activeSlide was not triggered when the bound variable was modified by my controller. I didn’t see anything in your PR that would address that. Were you seeing the same issue?

Line 56 from ionicSlideBox.js:

  $scope.$watch('activeSlide', function(nv) {
        if(angular.isDefined(nv)){
          slider.slide(nv);
        }   
      }); 

Actually, I just fixed this PR again.

New PR : https://github.com/driftyco/ionic/pull/400

@gavares the $scope.$watch('activeSlide' ... actually WON’T properly change the slide when first initialized. That’s because the watch starts before the slide is actually loaded. The activeSlide needs to be part of the slideBox setup process. That’s what my PR fixes.

I’m trying your latest fixes and now I can’t seem to find any way to get notified when the active slide changes. I’ve tried: active-slide=“deckIndex” and then doing:

	$scope.$watch('deckIndex', function(newValue, oldValue) {
		log.info('deckIndex changed. oldValue: ' + oldValue + ', newValue: ' + newValue);
	});

…but it’s not firing.

It’s also not firing slideBox.slideChanged either, anymore. Did something go missing with the events?

This is ionic master, as of 1385e7c9e9e2824ba2e625c35b7c7d89ee64d2e3.

@RangerRick If you use the newest release (0.9.20), you won’t have to rely on my PR. The fixes I made are incorporated in the currently release.

To monitor slide change events, just use this :

<slide-box id="intro-slide-box" active-slide="activeSlideValue" on-slide-changed="slideChanged(index)" class="has-header">

and

// Called each time the slide changes
$scope.slideChanged = function(index) { console.log('Slide changed to ' + index); }
2 Likes

Ahhhh! OK, “on-slide-changed” was what I was missing. Got everything working nicely, thanks!