Reputation: 8636
My View Model has an observable array of objects of WizardSteps,
var steps = [
new WizardStep(1, "step1", viewModel1),
new WizardStep(2, "step2", viewModel2),
];
self.stepModels = ko.observableArray(steps)
WizardStep just has an id, name and a personViewModel. viewModel1, viewModel2 are two PersonViewModels which contains name, age and phone number.
I can access stepModels by index $root.stepModels()[0].viewModel.name
and get the name of the viewModel1. But I need to access it by step name, e.g.'step1'.
How can I do this?
Upvotes: 0
Views: 2646
Reputation: 638
I had to create a 'wizard' type feature using knockout sometime ago. You could do something like this:
var steps = ko.observableArray([
{ stepName: "step1", person: viewModel1 },
{ stepName: "step1", person: viewModel2 }
]);
Firstly, it is worth noting that your steps array need not be an observable if you're not going to be modifying it once it has been populated. Second, you also might not need to have a step number - I assume that is what the 1 represents in the line:
new WizardStep(1, "step1")
Because arrays are ordered you're storing information you already have which is contained in the index of each element in your steps array. i.e. steps[0] would be step1 and so forth. If you need to keep track of where you are in your wizard you can create an observable in your viewModel and a function to set the step you're currently on like so:
var self = this;
self.currentStep = ko.observable(0); // starting step
self.goToStep = function(index){
self.currentStep(index);
};
Or you could:
var self = this;
self.currentStep = ko.observable(steps()[0]); // starting step
self.goToStep = function(index){
self.currentStep(steps()[index]);
// if you only need the viewModel associated with this step you could use:
self.currentPerson(steps()[index].viewModel.name);
};
In your view you can then use a knockout if binding to conditionally show or hide the step you are currently on / simply render the viewModel held in self.currentStep() and data-bind to a click event, for example.
If you really want to be able to access the step by stepName then you can use knockouts arrayFirst utility function:
self.getStepByName = function(stepName){
return ko.utils.arrayFirst(steps(), function(step) {
return step.stepName() === stepName;
});
};
I'll let you to fill in the blanks and the missing declarations. You could also do something using computeds or writable computeds. At the end of the day there are many ways to skin a cat. I'm sure any one of the solutions offered here are viable.
Upvotes: 1
Reputation: 23397
If you need to access the models often, it might be easier and faster to create an object that uses the step value as a key:
var WizardStep = function(id, name) {
this.id = id;
this.name = name;
};
var steps = [
new WizardStep(1, "step1"),
new WizardStep(2, "step2"),
];
var stepsByName = steps.reduce(function(result, step) {
result[step.name] = step;
return result;
}, {});
// The object:
console.log(JSON.stringify(stepsByName, null, 2));
// Get a step by name:
console.log(stepsByName["step1"]);
Upvotes: 1
Reputation: 7641
You can use "filter" array function:
var foundModel = <container object>.stepModels().filter(function(model) { return model.name === "modelName"; })[0];
if(!!foundModel) {
// some code working with found model
}
It is better to hold such a function in the model and not to put calculations into html markup.
Upvotes: 1