10

I am using Knockout js. I have a view model that contains an array of objects and I want to allow the user to edit one of the objects using a wizard style interface. The issue I have is the wizard will show different steps depending on what choices are made. For instance:

  • If the user selects 'Yes' on step 1 then I display step 2a
  • If the user selects 'No' on step 1 then I display step 2b (ie. a different dialog form)

This goes on so that the paths through the wizard are not linear.

My question is do I bind all the possible wizard UI steps to the view model at start up even though some steps will never be shown and the bindings on some screens will be invalid (eg. step 5 may bind to viewModel.theObject.PropertyA.PropertyB.PropertyC() but PropertyB is still null at step 1).

A better way may be to bind to the UI steps as they are displayed but my problem is then there I am not aware of a good way to 'unbind' the model once the step has completed so I could end up with the step bound to multiple objects from the original list!

Mark Robinson
  • 13,128
  • 13
  • 63
  • 81

1 Answers1

13

I think that a good way to do this is to have your view model be an array of steps and bind your UI to the "selectedStep". Then, each step can dynamically choose which template that it wants to use (like in this post).

Here is a rough sample of the idea: http://jsfiddle.net/rniemeyer/SSY6n/

This way the template bindings handles generating/binding/cleaning up the dynamic content based on whatever step is selected. If the steps are in an observableArray, then you could even dynamically add steps. Maybe you have a list of all of the possible steps and then have an "activeSteps" array that represents the steps that are currently valid based on the user's choices.

RP Niemeyer
  • 114,592
  • 18
  • 291
  • 211
  • Thanks, Ryan. A very interesting and creative approach. As I'm fairly well into my development now I may try and get by with guarding uninitialized properties with "data-bind='if: xxx" statements which seems to be working for now. Your solution if far more elegant though! PS - Great fan of your blog (www.knockmeout.net). Keep up the fantastic work! – Mark Robinson Sep 16 '11 at 12:53
  • @RPNiemeyer I am using ASP.net MVC 4 and have a `[Serializable]` wizard that uses separate pages (from an MVC book) and is also using `[DataAnnotations]` with client-side validation. I'm wondering if your updated sample would work to replace the pages but continue using the validation. Any thoughts? – REMESQ Apr 19 '12 at 03:00
  • I'm implementing something similar, and one thing you can do instead of null checking data-bindings is just adding a binding for visible:. If it's a truthy value, like a string or object, the visible evaluates nulls and empty strings as false and hides the element. Would not recommend for numeric values, especially if you want it to display for zeroes. – Patrick M Jul 09 '12 at 19:59
  • Hi Niemeyer, I am trying to use your example. In the source code however it references http://www.aegema.com/jsfiddle/jquery.tmpl.min.js. Without reference to this script it doesnt work. Can you tell me what is in that script (since it is minimalized I cant read it). I was in the assumption that ko.js, jquery.js and custom js for implementing viewmodel and functions would be enough). – Mounhim Jul 24 '12 at 18:46
  • 1
    KO 2.0+ no longer requires jQuery Templates to do templating. The samples in this answer were referencing KO 1.2.1. I updated both fiddles that I posted to reference KO 2.1 without jQuery Templates. – RP Niemeyer Jul 24 '12 at 19:19
  • Thanks. Great example and I got it working now. I still have a question though. Dont know if it is ok to put it here or start a new question. How would you handle validation? I want to achieve that the next button is enabled until validations are met. Can you help? – Mounhim Jul 29 '12 at 00:26
  • Sorry, but does anyone know why some of the HTML is in script tags? Why do you need them? – AlbatrossCafe May 28 '15 at 23:16
  • 1
    @AlbatrossCafe - when this answer was written, Knockout did not yet support its native template engine (using "with", "foreach", "if" bindings inline), so it uses only the `template` binding. The script tags are templates. – RP Niemeyer May 29 '15 at 13:32