I'm using Kendo UI Wizard, with a form that's being fed a viewmodel. That's working as intended, and it's submitting back to the controller.
What I would like to setup is a confirmation as the second/final step of the wizard, but with the 1:1 (property:field) limitation I'm having some difficulty wrapping my mind around how to do this.
(If the first step is ~6 fields of data, I want the second/final step to be those same fields but readonly, giving the user a chance to review changes before hitting submit.)
@model MyApp.Web.Areas.Application.ViewModels.AddressViewModel
@(Html.Kendo().Wizard()
.Name("ChangeAddressWizard")
.Events(ev => ev.Done("onDone"))
.Tag("form")
.HtmlAttributes(new { @novalidate = "", action = Url.Action("ChangeAddress", "Home"), method = "post" })
.ContentPosition(WizardContentPosition.Right )
.Steps(s => {
s.Add<MyApp.Web.Areas.Application.ViewModels.AddressModel>()
.Title("Change Address")
.Form(f => f
.Validatable(v => {
v.ValidateOnBlur(true);
v.ValidationSummary(vs => vs.Enable(false));
})
.FormData(Model)
.Layout("grid")
.Events(e => e.Change("onChange"))
.Grid(g => g.Cols(2).Gutter(20))
.Items(items => {
items.AddGroup()
.Label("Address Info")
.Layout("grid")
.Items(i => {
i.Add().Field(p => p.City)
.Label(l => @Html.LabelFor(p => p.City));
i.Add().Field(p => p.State)
.Label(l => @Html.LabelFor(p => p.State));
i.Add().Field(p => p.Zip)
.Label(l => @Html.LabelFor(p => p.Zip));
i.Add().Field(p => p.Country)
.Label(l => @Html.LabelFor(p => p.Country));
});
})
)
.Buttons(b => {
b.Next();
});
s.Add<MyApp.Web.Areas.Application.ViewModels.AddressViewModel>()
.Title("Review Changes")
.Form(f => f
.FormData(Model)
.Layout("grid")
.Events(e => e.Change("onChange"))
.Grid(g => g.Cols(2).Gutter(20))
.Items(items =>
{
//Below fields would be readonly on this step
i.Add().Field(p => p.City)
.Label(l => @Html.LabelFor(p => p.City));
i.Add().Field(p => p.State)
.Label(l => @Html.LabelFor(p => p.State));
i.Add().Field(p => p.Zip)
.Label(l => @Html.LabelFor(p => p.Zip));
i.Add().Field(p => p.Country)
.Label(l => @Html.LabelFor(p => p.Country));
});
})
)
.Buttons(b => {
b.Previous();
b.Done();
});
}))
</div>
Initially I tried the above but the fields are blank on the second step. From my understanding this is due to each property mapped by name from the model to the input.
I see a couple options but they all seem kind of hacky...
Setup fields that aren't mapped to the model and update them via script and use those to display on the confirmation/review step
Write my own "step" that really just toggles all the fields to read only
Is there a better way than either of these options? In the example I provided It's trimmed down to 4 fields but some of my use cases are multiple steps of fields. I feel like there should be a simple and obvious way to show the entirety of a form as read only on the final step without breaking the 1 property : 1 field rule. (This could be a limitation with Kendo functionality)
I've been racking my brain on this one, any pointers would be appreciated.
CodePudding user response:
You will have to add a final step and use JavaScript to populate the summary.
When creating a Form field
i.Add().Field(p => p.City)
.Label(l => @Html.LabelFor(p => p.City));
essentially an <input id="City"/>
is generated. The first issue when adding a final step with the same fields is that you will end up with DOM elements with the same id. The second one is that the inputs will be blank (or completed with data passed via the Model during the component initialization), but will not reflect any changes the user has made.
You can add a Summary step:
s.Add().Title("Summary").Content("<ul id='content-container'></ul>")
.Buttons(b =>
{
b.Previous();
b.Done();
});
and an Activate event handler. Use the handler to get all the Forms in the Wizard. The Form API will allow you to get the current values for each field and you can list them in the summary step:
function onActivate(e){
if (e.step.options.index == 2) { //current final step
var formElements = e.sender.wrapper.find(".k-form");
//the wizard in the example contains two forms. Iterate them and list the values.
formElements.each(function(idx,elm){
var form = $(elm).getKendoForm();
var kvp = JSON.parse(JSON.stringify(form.editable.options.model))
for (var key in kvp){
$("#content-container").append(`<li><b>${key}</b> : ${kvp[key]} </li>`)
}
})
}
}
Here is a simple example where Kendo's Form integration demo is extended with a summary step. Sure, you'll have to fine tune it if you have DropDowns and/or other components where a value is submitted, but some descriptive text is being displayed, mask passwords, etc., but I hope you get the idea.