Step by step

The next component to examine is the one that represents a step in the questionnaire and shows the associated questions:

// packages/wizard/src/view/Step.js
Ext.define('Wizard.view.wizard.Step', {
    extend: 'Ext.form.Panel',
    xtype: 'wizard-step',
    cls: 'wizard-step',


    defaults: {
        labelSeparator: '', labelAlign: 'top',
        labelWidth: 250, msgTarget: 'side',
        width: '100%'
    },

    config: {
        step: null
    },

    modelValidation: true,

    applyStep: function(step) {
        
        this.add({
            xtype: 'container',
            cls: 'wizard-step-introduction',
            html: step.get('introduction')
        });

        step.questions().each(function(question) {
            this.add({
                xtype: question.get('type'),
                fieldLabel: question.get('questionText'),
                required: question.get('required'),
                bind: '{question.answer}',
                viewModel: 'progress-step'
            }).getViewModel().set('question', question);
        }, this);

        step.isValid();
    }
});

There's the standard setup for Ext.form.Panel here, configuring labels, and so on. Once again, I created a custom step config that we bound to in the parent Wizard panel's addStepPane method and use the matching apply method to build out the contents of the form.

Note how I have set the modelValidation config to true. As a result of my prototype earlier in the chapter, I know that this is great way to avoid code duplication by creating validation on a model and have it take effect in the form UI. When building the questions for the step in applyStep, I make sure and bind question.answer to the form field value. This means that any validation on the question model's answer field will be applied to the form field UI automatically.

All of the other attributes of the form field are built dynamically from the question data, such as the label and the field type. The final thing to note here is that I use a separate view model and immediately populate it with the question. Look at the code for this view model:

// packages/wizard/src/view/ProgressStepModel.js
Ext.define('Wizard.view.wizard.ProgressStepModel', {
    extend: 'Ext.app.ViewModel',
    alias: 'viewmodel.progress-step',
    
    data: {
        question: null
    },

    formulas: {
        isValid: {
            bind: {
                bindTo: '{question}',
                deep: true
            },
            get: function() {
                return this.get('step').isValid();
            }
        }
    }
});

It's nothing complicated; it's just a little bit long to define inline and so I moved it to a separate file. The code here should also look very familiar because it's the same as the code from my prototype that I showed earlier in the chapter under the heading "A Binding Trick". I knew this would come in useful!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset