Reputation: 848
I have the following JS object:
var TournamentPlayer = function (PlayerName, Handicap, Nationality) {
var self = this;
self.PlayerName = ko.observable(PlayerName).extend({
required: {
message: 'Player No. ' + $index() + ' is required.' // How to get $index() here?
}
});
self.Handicap = ko.observable(Handicap);
self.Nationality = ko.observable(Nationality);
}
I need to capture details of four players where PlayerName
is required, I am using the following code to add empty TournamentPlayer
objects in the parent JS object:
self.TournamentPlayers.push(new TournamentPlayer('', 0, ''));
self.TournamentPlayers.push(new TournamentPlayer('', 0, ''));
self.TournamentPlayers.push(new TournamentPlayer('', 0, ''));
self.TournamentPlayers.push(new TournamentPlayer('', 0, ''));
I want to get KO
data like the observable
value, $index()
, $data()
etc in the KOValidation
extend
function, how can I do this?
Upvotes: 2
Views: 53
Reputation: 63709
My first thought was to do this by coding the index into the view models, thus making it unit testable:
var TournamentPlayer = function (PlayerName, Handicap, Nationality, GetNr) {
var self = this;
self.PlayerName = ko.observable(PlayerName).extend({
required: {
message: 'Player No. ' + GetNr(self) + ' is required.'
}
});
}
Then instantiate them like this:
var Root = function() {
self.TournamentPlayers = ko.observableArray([]);
self.GetNr = function(p) { return self.TournamentPlayers.indexOf(p); };
self.TournamentPlayers.push(new TournamentPlayer('', 0, '', self.GetNr));
// etc.
}
But this does not work correctly, because GetNr(self)
is called once, upon constructing the Player, before it has been push
ed into the array (thus they all get a nr of -1
).
Unfortunately, the message
of an extension cannot be (AFAICT) an observable. There is formatting for custom rules, where I guess you could "inherit" from the default required
rule and give it formattable messages.
With all that, I'm afraid the best way to do what you want is render custom messages in your markup, something like this:
var TournamentPlayer = function (PlayerName, Handicap, Nationality) {
var self = this;
self.PlayerName = ko.observable(PlayerName).extend({
required: {
message: 'Player Name is required.'
}
});
}
var Root = function() {
self.TournamentPlayers = ko.observableArray([]);
self.GetNr = function(p) { return self.TournamentPlayers.indexOf(p); };
self.TournamentPlayers.push(new TournamentPlayer('', 0, ''));
self.TournamentPlayers.push(new TournamentPlayer('', 0, ''));
self.TournamentPlayers.push(new TournamentPlayer('', 0, ''));
self.TournamentPlayers.push(new TournamentPlayer('', 0, ''));
}
ko.applyBindings(new Root());
.validationMessage { display: none; }
.customValidationMessage { color: red; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout-validation/2.0.3/knockout.validation.min.js"></script>
<ul data-bind="foreach: TournamentPlayers">
<li>
Player Name:
<input data-bind="textInput: PlayerName">
<span class="customValidationMessage" data-bind="visible: !PlayerName.isValid()">
Player
<span data-bind="text: $index() + 1"></span>
is required.
</span>
</li>
</ul>
Not pretty, and I welcome competing answers, but best I could come up with so far...
Upvotes: 1