Is there a way to find which DOM element that is bound to a particular observable?

6,422 views
Skip to first unread message

gaffe

unread,
Nov 18, 2011, 2:19:35 PM11/18/11
to KnockoutJS
Hey guys,

I have an application where a large list is being generated by
knockout templates. Users have requested that I make the div element
that contains that list scroll down to the first selected element by
default.

I wrote a function that will scroll to the top a particular DOM
object, but the JavaScript that loops through my list is in a place
where I don't have access to the event object. I do have access to the
observable however which is bound to it.

Is there any way to find which DOM object is bound to that observable?

Thanks,
Enis

Koviko

unread,
Nov 18, 2011, 3:23:10 PM11/18/11
to knock...@googlegroups.com
I would recommend using afterRender or afterAdd.

<ul data-bind="foreach: { data: items, afterRender: scrollListToSelectedItem }">
    <li>...</li>
</ul>

gaffe

unread,
Nov 18, 2011, 7:24:26 PM11/18/11
to KnockoutJS
Thanks, I appreciate the suggestion but in my case its a bit more
complex, I really need to know
if its possible to find the DOM element from the observable.

In your example below, inside scrollisttoselecteditem, I still need to
figure out which Dom element to scroll to. When I am populating the
items I can store the observable of the first item that is selected,
but I don't have which Dom element it was bound to.

mcoolin

unread,
Nov 18, 2011, 7:26:59 PM11/18/11
to knock...@googlegroups.com
just a small point but observables can be bound to more than one object.

Koviko

unread,
Nov 19, 2011, 7:18:53 AM11/19/11
to knock...@googlegroups.com
 I still need to figure out which Dom element to scroll to . When I am populating the items I can store the observable of the first item that is selected, but I don't have which Dom element it was bound to.

I'm not sure that I follow. You are saying that the only indication that you have in your presentation that an item is selected is an observable in your view-model?

You should have some sort of indication in your HTML that an item is selected, such as a class named "selected." Your scroll function is a part of your presentation logic and should be able to function with or without Knockout.

<ul data-bind="foreach: { data: items, afterRender: scrollListToSelectedItem }">
    <li data-bind="css: { selected: isSelected }">...</li>
</ul>

Ilia Ablamonov

unread,
Nov 19, 2011, 10:59:05 AM11/19/11
to knock...@googlegroups.com
I'm using the following simple binding:

ko.bindingHandlers.element = {
    init: function(element, valueAccessor) {
        valueAccessor()(element);
    }
};

...somewhere in view model:

<model for each item>.element = ko.observable();

and in html:

<ul data-bind="template: ...">
    <li data-bind="element: element, ..."></li>
</ul>

Koviko

unread,
Nov 20, 2011, 9:30:20 AM11/20/11
to knock...@googlegroups.com
While that is doable, it does not follow that pattern of MVVM. You are essentially skipping the View-Model by coupling the View and Model together.

John Rayner

unread,
Nov 21, 2011, 8:57:49 AM11/21/11
to knock...@googlegroups.com
I might be missing something, but I think this could work:

ko.bindingHandlers.intoView = {
    update: function(element, valueAccessor) {
        if(valueAccessor()) element.scrollIntoView();
    }
};

with ...
<model for each item>.intoView = ko.observable(false);

and ...
<li data-bind="intoViewintoView, ..."></li>

If you use this binding on your collection items, then you can call intoView(true) and the relevant div should appear on-screen.

Cheers,
John

gaffe

unread,
Nov 21, 2011, 10:53:38 AM11/21/11
to KnockoutJS
This is pointing me in the right direction, but I am not using jquery
templates, I am using knockout 1.3 style ones, anyone know the syntax
for afterrender for a template like:

<!-- ko foreach: viewModel.mystuff() -->

I tried

<!-- ko foreach: viewModel.mystuff() , afterRender: myfun() -->

but that seems to do nothing...

Koviko

unread,
Nov 21, 2011, 11:15:05 AM11/21/11
to knock...@googlegroups.com
Exactly as I posted before. The HTML comments used for Knockout's element-less bindings use the same context as regular bindings. Also, note that you should omit the parentheses for myfun. Without parentheses, you are sending the function object. With the parentheses, you are sending the result of the function being ran (which likely isn't what you want).

<!-- ko foreach: { data: viewModel.mystuff(), afterRender: myfun } -->

Guillaume

unread,
Nov 21, 2011, 11:16:13 AM11/21/11
to KnockoutJS
You could try to generate an ID for the element depending on an ID in
your viewModel item.

<li data-bind="attr: { id: 'item-' + id }"></li>

and get it with document.getElementById() in the js

but i'm bot sure it's ok because I think knockoutjs also generate some
ids when you bind events

Koviko

unread,
Nov 21, 2011, 11:16:24 AM11/21/11
to knock...@googlegroups.com
Knockout's element-less bindings use the same syntax, not context. Sorry about the typo.
Reply all
Reply to author
Forward
0 new messages