Data-Binding, foreach - How to add a condition?

1,457 views
Skip to first unread message

Weekends

unread,
Feb 23, 2011, 3:11:16 PM2/23/11
to knock...@googlegroups.com
Given a View like:

<div id="comment-100">
   <ul data-bind='template: { name: "attachmentListTemplate", foreach: attachmentsModel.Attachments }'> </ul>
</div>
<div id="comment-102">
   <ul data-bind='template: { name: "attachmentListTemplate", foreach: attachmentsModel.Attachments }'> </ul>
</div>
<div id="comment-103">
   <ul data-bind='template: { name: "attachmentListTemplate", foreach: attachmentsModel.Attachments }'> </ul>
</div>
<div id="comment-104">
   <ul data-bind='template: { name: "attachmentListTemplate", foreach: attachmentsModel.Attachments }'> </ul>
</div>
<div id="comment-105">
   <ul data-bind='template: { name: "attachmentListTemplate", foreach: attachmentsModel.Attachments }'> </ul>
</div>


What I would like to do is update the data-bind, to do something like foreach: attachmentsModel.Attachments.where(attachmentsModel.Attachments.comment_id == 105). Allowing me to only show the attachments tagged to that comment.

I thought about just adding an {if} condition inside the jquery Template, but that won't work as I only want to render that template once on the page, while the comments above are rendering by looping through an array. 

Any suggestions? Thanks






Ω Alisson

unread,
Feb 23, 2011, 3:14:23 PM2/23/11
to knock...@googlegroups.com
Yes, write dependent observables!

Weekends

unread,
Feb 23, 2011, 3:20:49 PM2/23/11
to knock...@googlegroups.com
A dependent observable for each comment? Or is there a way to have one dependent observable for all comments, the # of comments is not static.

Also, is there a way to pass a var in the data-bind to the template? 

I tried this:
<ul data-bind='template: { name: "attachmentListTemplate", foreach: attachmentsModel.convAttachments, options: {current_cmt_id: <%=comment.id%>} }'> </ul>
<script type="text/html" id="attachmentListTemplate">
<li>
${current_cmt_id} - <a href="${link}" class="fancyIFrame clearfix">${title}</a>
</li>
</script>

But the current_cmt_id never made it to the template. thanks!

rpn

unread,
Feb 23, 2011, 4:11:10 PM2/23/11
to knock...@googlegroups.com
If you are using the latest knockout code, you can pass templateOptions into the template binding and then access them by $item.yourkey.  

<ul data-bind='template: { name: "attachmentListTemplate", foreach: attachmentsModel.convAttachments, templateOptions: {current_cmt_id: <%=comment.id%>} }'> </ul>
<script type="text/html" id="attachmentListTemplate">
<li>
${$item.current_cmt_id} - <a href="${link}" class="fancyIFrame clearfix">${title}</a>
</li>
</script>

Weekends

unread,
Feb 23, 2011, 6:33:17 PM2/23/11
to knock...@googlegroups.com
Thanks RPN, I think that will work eventually, curious if that's the fastest option? But I can look into that later.

Here's what I did based on your reply:

<ul data-bind='template: { name: "attachmentListTemplate", foreach: attachmentsModel.convAttachments, templateOptions: {current_cmt_id: <%=comment.id%>} }'> </ul>

<script type="text/html" id="attachmentListTemplate">
{{if $item.current_cmt_id == id }}
<li>
<a href="${link}" class="fancyIFrame clearfix">${title}</a>
</li>
{{/if}}
</script>

no luck yet though. Is that look right to you>? thxs

rpn

unread,
Feb 23, 2011, 9:32:07 PM2/23/11
to knock...@googlegroups.com
Looks ok to me.  Just make sure you are using the latest Knockout code, as templateOptions was not supported in 1.12.   I saw you had a question on StackOverflow that was answered, so maybe your only problem was that id should have been id() in your if statement?

If you do not choose to use templateOptions, then you could choose to pass a filtered version of your collection into the foreach of each template binding.  This would be using something like ko.utils.arrayFilter like: http://jsfiddle.net/rniemeyer/Kbszh/

Hope this helps.

Weekends

unread,
Feb 24, 2011, 2:15:06 PM2/24/11
to knock...@googlegroups.com
Thanks RPN. Turns out the issue was here: 
{{if $item.current_cmt_id == id }}
I needed it to be
{{if $item.current_cmt_id == id() }} with the parenthesis

While that's working now, I'm noticing that when the array is updated, the templates are not rerunning. I'm not sure why that is just yet, perhaps your arrayFilter idea is the way to go. Will that refresh when the array changes?

thanks again

Weekends

unread,
Feb 24, 2011, 2:36:02 PM2/24/11
to knock...@googlegroups.com
Is something like this possible? It's not erring, but also not outputting :)

<ul class="attachmentList" data-bind="template: { name: 'attachmentListTemplate', foreach: attachmentsModel.convAttachments().comment_id ==  412 }"><ul>

rpn

unread,
Feb 24, 2011, 2:55:47 PM2/24/11
to knock...@googlegroups.com
If you are using an observableArray, then your UI should respond to adding/removing items from the array. If the properties of the items in the array are observable, then your UI should update when they are edited.  Update the little sample to just show them being observable: http://jsfiddle.net/rniemeyer/baAaH/

I don't know about the last syntax, your statement will result in a true/false answer rather than a filtered list of items in an array.  

Hope this helps.

Weekends

unread,
Feb 24, 2011, 5:37:28 PM2/24/11
to knock...@googlegroups.com
Thanks RPN, very nice of you to put that fiddle together. It looks like the issue I'm experiencing is because of injecting a new data-bind after the KO Binding has been applied. Given that issue is very different, I started a new thread: https://groups.google.com/d/topic/knockoutjs/P3FM8CgeR-w/discussion

Thanks again! 
Reply all
Reply to author
Forward
0 new messages