6

Im using https://github.com/mgonto/angular-wizard to create an angular wizard whose steps can be called from route params:

  • .../step/1
  • .../step/2

etc.

So I've created this controller:

.controller('createOrganizer', ['$scope', 'WizardHandler' , '$routeParams',
    function($scope,WizardHandler,$routeParams)
    {
        //$scope.data = {};
        $step = $routeParams.step;
        WizardHandler.wizard().goTo($step);     
    }])

The proper linking and routing were created correctly on app.js and the index.html

But when I get into the urls, I get this:

TypeError: Cannot call method 'goTo' of undefined

Is this the way to pre-select an angular-wizard step using url parameters?

================= Update =====================

I tried with something like this:

.controller('createOrganizer', ['$scope', 'WizardHandler' , '$routeParams', function($scope,WizardHandler,$routeParams) { $step = $routeParams.step;

    $scope.$watch(WizardHandler.wizard(), function(step) {
            WizardHandler.wizard().goTo($step);
    });
}])

The idea is to ise watch to tell me when WizardHandler.wizard() is instantiated in order to call the .goTo method. With this controller im getting this error:

TypeError: Cannot set property 'selected' of undefined

Not sure if i am using watch correctly. I even tested the step variable and it is ok, showing the same value as the url.

================= Solved! =====================

    var step = parseInt($routeParams.step); // Important, as routeParams returns an String: the wizardHandler uses either an integer number or a string name of step. So I am parsing the number to prevent confusion.
    $scope.$watch(
    function() {return WizardHandler.wizard();}, 
    function (wizard) {
    if (wizard) wizard.goTo(step);
    });

I added an init(step) function that handles the initial values of some values i need and also prevents error caused by urls like .../step/SOMERANDOMSTRING

Thanks to GregL for your help!

kennyvivas
  • 101
  • 1
  • 8

2 Answers2

4

From reading through the source code quickly, my first guess would be that you have used a <wizard> element with a name property specified, but you have not passed that same name to WizardHandler.wizard(). In the code, if you don't specify a name argument to WizardHandler.wizard(), it will use the default name, which is the name used by a <wizard> with no name attribute.

Since you are not getting back the wizard you are intending when you call WizardHandler.wizard(), it resolves to undefined and calling goTo() will fail with the error you got.

At the very least, separate the getting of the wizard and the .goTo() call to add a check in to make sure you got a valid wizard:

.controller('createOrganizer', ['$scope', 'WizardHandler' , '$routeParams',
    function($scope,WizardHandler,$routeParams)
    {
        //$scope.data = {};
        $step = $routeParams.step;
        var wizard = WizardHandler.wizard();
        if (wizard)
            wizard.goTo($step);
    }]);        

There should probably be a var keyword before that $step assignment, too, and as a convention, only Angular core things should start with a $, or jQuery selection variables.

EDIT: You could also try using a $watch() to get notified when the wizard is loaded, however there is no guarantee that the $digest() cycle will be called immediately after the wizard is loaded, so you would be relying on the assumption that the $apply/$digest cycle is run sometime after the wizard is correctly added to the WizardHandler's cache.

You would do this like so:

.controller('createOrganizer', ['$scope', 'WizardHandler' , '$routeParams',
    function($scope,WizardHandler,$routeParams)
    {
        //$scope.data = {};
        $step = $routeParams.step;
        $scope.$watch(function() {
            return WizardHandler.wizard();
        }, function (wizard) {
            if (wizard)
                wizard.goTo($step);
        });
    }]);  
GregL
  • 37,147
  • 8
  • 62
  • 67
  • *Disclaimer:* I have not yet used this component to verify my answer. Though it may just be the ideal component for an app I am working on at the moment, and your question alerted me to it, so thanks for asking it! – GregL Feb 26 '14 at 02:11
  • I think it is more like a race condition. The Wizard.Handler.wizard() property is not even instantiated when I ask for the goTo method. – kennyvivas Feb 26 '14 at 04:07
  • I tried with something like this: .controller('createOrganizer', ['$scope', 'WizardHandler' , '$routeParams', function($scope,WizardHandler,$routeParams) { $step = $routeParams.step; $scope.$watch(WizardHandler.wizard(), function(step) { WizardHandler.wizard().goTo($step); }); }]) – kennyvivas Feb 26 '14 at 04:07
  • @kennyvivas Good idea about using `$watch()`, I updated my answer to show the correct way of doing what you tried. – GregL Feb 26 '14 at 05:42
  • 2
    Great! Actually you just nailed! but I had to make some minor amends to the code in order to make it work (stupid one actually, i had to parseInt the routeParams step variable.) Check on the update and thanks a lot! – kennyvivas Feb 26 '14 at 16:37
0

You are probably trying to access the wizard instance when it is not yet initialized. If you wrap it in a $timeout, it should work (and is less complicated compared to $watch solution above):

$timeout(function() {
    WizardHandler.wizard().goTo($step); 
});
Tadej Krevh
  • 417
  • 6
  • 7