Niemeyer가 제공 한 답변을 기반으로 간단한 마법사를 만들었습니다. 이것은 잘 작동합니다. 유효성 검사를 추가하고 싶습니다. Firstname 필드에 필요한 유효성을 추가했습니다. 이 필드를 비워두면 오류가 표시됩니다. 하지만 성공할 수없는 것은 다음과 같습니다. 현재 단계에서 모델의 유효성을 검사하고 오류가 있는지 여부에 따라 다음에 사용 또는 사용 안 함을 설정합니다. 다음 버튼을 활성화 또는 비활성화하기가 너무 어려우면 괜찮습니다. 오류가 발생하면 버튼을 비활성화하지 않고도 살 수 있습니다. 오류가있을 때 사용자가 다음 단계로 진행하지 못하는 한.각 단계에서 Knockout.js 마법사 유효성 검사
. 내보기는 다음과 같습니다
//model is retrieved from server model
<script type="text/javascript">
var serverViewModel = @Html.Raw(Json.Encode(Model));
</script>
<h2>Test with wizard using Knockout.js</h2>
<div data-bind="template: { name: 'currentTmpl', data: currentStep }"></div>
<hr/>
<button data-bind="click: goPrevious, enable: canGoPrevious">Previous</button>
<button data-bind="click: goNext, enable: canGoNext">Next</button>
<script id="currentTmpl" type="text/html">
<h2 data-bind="text: name"></h2>
<div data-bind="template: { name: getTemplate, data: model }"></div>
</script>
<script id="nameTmpl" type="text/html">
<fieldset>
<legend>Naamgegevens</legend>
<p data-bind="css: { error: FirstName.hasError }">
@Html.LabelFor(model => model.FirstName)
@Html.TextBoxFor(model => model.FirstName, new { data_bind = "value: FirstName, valueUpdate: 'afterkeydown'"})
<span data-bind='visible: FirstName.hasError, text: FirstName.validationMessage'> </span>
</p>
@Html.LabelFor(model => model.LastName)
@Html.TextBoxFor(model => model.LastName, new { data_bind = "value: LastName" })
</fieldset>
</script>
<script id="addressTmpl" type="text/html">
<fieldset>
<legend>Adresgegevens</legend>
@Html.LabelFor(model => model.Address)
@Html.TextBoxFor(model => model.Address, new { data_bind = "value: Address" })
@Html.LabelFor(model => model.PostalCode)
@Html.TextBoxFor(model => model.PostalCode, new { data_bind = "value: PostalCode" })
@Html.LabelFor(model => model.City)
@Html.TextBoxFor(model => model.City, new { data_bind = "value: City" })
</fieldset>
</script>
<script id="confirmTmpl" type="text/html">
<fieldset>
<legend>Naamgegevens</legend>
@Html.LabelFor(model => model.FirstName)
<b><span data-bind="text:NameModel.FirstName"></span></b>
<br/>
@Html.LabelFor(model => model.LastName)
<b><span data-bind="text:NameModel.LastName"></span></b>
</fieldset>
<fieldset>
<legend>Adresgegevens</legend>
@Html.LabelFor(model => model.Address)
<b><span data-bind="text:AddressModel.Address"></span></b>
<br/>
@Html.LabelFor(model => model.PostalCode)
<b><span data-bind="text:AddressModel.PostalCode"></span></b>
<br/>
@Html.LabelFor(model => model.City)
<b><span data-bind="text:AddressModel.City"></span></b>
</fieldset>
<button data-bind="click: confirm">Confirm</button>
</script>
<script type='text/javascript'>
$(function() {
if (typeof(ViewModel) != "undefined") {
ko.applyBindings(new ViewModel(serverViewModel));
} else {
alert("Wizard not defined!");
}
});
</script>
knockout.js 구현은 다음과 같습니다
function Step(id, name, template, model) {
var self = this;
self.id = id;
self.name = ko.observable(name);
self.template = template;
self.model = ko.observable(model);
self.getTemplate = function() {
return self.template;
};
}
function ViewModel(model) {
var self = this;
self.nameModel = new NameModel(model);
self.addressModel = new AddressModel(model);
self.stepModels = ko.observableArray([
new Step(1, "Step1", "nameTmpl", self.nameModel),
new Step(2, "Step2", "addressTmpl", self.addressModel),
new Step(3, "Confirmation", "confirmTmpl", {NameModel: self.nameModel, AddressModel:self.addressModel})]);
self.currentStep = ko.observable(self.stepModels()[0]);
self.currentIndex = ko.dependentObservable(function() {
return self.stepModels.indexOf(self.currentStep());
});
self.getTemplate = function(data) {
return self.currentStep().template();
};
self.canGoNext = ko.dependentObservable(function() {
return self.currentIndex() < self.stepModels().length - 1;
});
self.goNext = function() {
if (self.canGoNext()) {
self.currentStep(self.stepModels()[self.currentIndex() + 1]);
}
};
self.canGoPrevious = ko.dependentObservable(function() {
return self.currentIndex() > 0;
});
self.goPrevious = function() {
if (self.canGoPrevious()) {
self.currentStep(self.stepModels()[self.currentIndex() - 1]);
}
};
}
NameModel = function (model) {
var self = this;
//Observables
self.FirstName = ko.observable(model.FirstName).extend({ required: "Please enter a first name" });;
self.LastName = ko.observable(model.LastName);
return self;
};
AddressModel = function(model) {
var self = this;
//Observables
self.Address = ko.observable(model.Address);
self.PostalCode = ko.observable(model.PostalCode);
self.City = ko.observable(model.City);
return self;
};
그리고 필드 FIRSTNAME에서 사용 된 내가 필요한 검증하기위한 확장을 추가했습니다 :
ko.extenders.required = function(target, overrideMessage) {
//add some sub-observables to our observable
target.hasError = ko.observable();
target.validationMessage = ko.observable();
//define a function to do validation
function validate(newValue) {
target.hasError(newValue ? false : true);
target.validationMessage(newValue ? "" : overrideMessage || "This field is required");
}
//initial validation
validate(target());
//validate whenever the value changes
target.subscribe(validate);
//return the original observable
return target;
};
나는 꽤 유사 할 것입니다. 그러나 모델 속성 중 어떤 것이 유효하지 않은지 (현재 코드는 최상위 소품 만 수행 할 것입니다) 보이는 "단계"객체에 대해 계산 된 일반을 넣을 것입니다. 보기 모델을 뷰에 묶는 것은'$ ('. validationMessage : visible')'클래스의 특정 클래스를 가진 요소를 찾고 모델에 로직을 유지하는 것을 피할 것이다. http://jsfiddle.net/rniemeyer/MK39r/23/ –
나는 그 해결책을 많이 좋아한다! 각 모델 클래스에서'modelIsValid'를 사용하는 것에 대해 생각해 보았습니다. 그러나 나는 그것이 결국 나쁘게 나쁘게 나쁘다고 생각했습니다. 그래도 Step에서 정의 할 생각은 없었습니다. 전에 JS에서 그런 식으로 반사를하지 않았습니다. 좋은 점 ... 항상 귀하의 의견에 감사드립니다, Ryan. – jimmym715
knockout.validation을 사용하여 해결했습니다.제 생각에는 요소가 보이는지를 조사하는 것보다 더 깔끔하다고 생각합니다. 답장으로 답장을 표시하겠습니다. 관심있는 사람이 있다면 나중에 knockout.validation이 사용 된 솔루션을 게시 할 수 있습니다. – Mounhim