Is it possible to access bound element from ko.computed function?
Something like this pseudo code (simplified for clarity):
<h1 id="id1" data-bind="visible: myComputed">
<h1 id="id2" data-bind="visible: myComputed">
<h1 id="id3" data-bind="visible: myComputed">
...
self.myComputed = ko.computed(function(){
return <BOUND_ELEMNT>.id == 'id2';
});
Resulting in only the second element showing.
Note: I'm aware I can have a separate computed for every element, but it is not possible in my case.
EDIT:
Ok - I'll give a more accurate example. The following is similar to what I have:
<section id="id1" data-bind="visible: myComputed1">A lot of code</section>
<section id="id2" data-bind="visible: myComputed2">different lots of code</section>
<section id="id3" data-bind="visible: myComputed3">Other lots of code</section>
...
// This field's value changes over time (between 'id1', 'id2' and 'id3').
// Some complex logic changes this field,
// and as a result only one h1 is showing at a time.
self.myField = ko.observable();
self.myComputed1 = ko.computed(function(){
return self.myField() == 'id1';
});
self.myComputed2 = ko.computed(function(){
return self.myField() == 'id2';
});
self.myComputed3 = ko.computed(function(){
return self.myField() == 'id3';
});
This is an ugly violation of the DRY principle, and I would like to find a way to refactor it. The pseudo code above may solve it, but I'm open for suggestions...
Make a custom binding handler that uses your observable to trigger the visibility. Something like this:
Change your HTML:
And a sample view model:
Here's a jsFiddle with a demo that changes the headerId after two seconds: http://jsfiddle.net/psteele/cq9GU/
You've created a short, simplified example, which is normally great. However, it feels like you've introduced an XY-problem instead. As such, this answer may or may not be helpful.
You're trying to introduce a dependency on the View in your ViewModel. It should be the other way around! Something like this would make more sense:
Note the use of the attr binding to set the id. Your ViewModel should be constructed accordingly:
Note: I'm leaving my other answer as an answer to the first bit of the question, maybe it'll help other users stumbling upon this question.
The question in the update is:
OP indicates in comments that answers focussing on the given example are preferred. The sample code can be easily refactored such that it doesn't violate DRY anymore. (PS. I still think the "why" behind wanting this structure is very important, but that doesn't prevent me from answering the question in the context of the given sample.)
Method 1 - One
h1
in the View - One item in the ViewModelUse the following View:
With this ViewModel:
Very DRY, functionally almost equivalent (except that the other 2
h1
elements aren't just invisible, they're not even in the DOM).Method 2 - Multiple
h1
s in the View - Multiple items in the ViewModelRefactor the View to a list structure (see note 4 in the foreach binding):
With the following ViewModel:
See this fiddle for a demo.
Method 3 - One
h1
in the View - Multiple items in the ViewModelWith this method you use the list like setup from method 2, but only render the currentitem. The View utilizes the
with
binding:The ViewModel is the same as in method 2. See this fiddle for a demo.