knockout can't find templates inside of views

1,777 views
Skip to first unread message

Joseph Gabriel

unread,
Feb 8, 2013, 5:17:19 PM2/8/13
to duran...@googlegroups.com
When activating a view, I'm having trouble getting knockout to find templates by id.  This error occurs when placing the template block anywhere in the same file as the view.  If the template block is placed in the main .cshtml file that is initially loaded, the template works fine.

Does anyone know what may be causing this?  I'm going to look into it over the weekend, but wanted to see if anyone has any ideas.  Hopefully it's just something I'm doing wrong.  Either way, I'll update this thread once I get it solved.

Rob Eisenberg

unread,
Feb 8, 2013, 5:18:12 PM2/8/13
to Joseph Gabriel, duran...@googlegroups.com
I'm confused. What is a template block?


On Fri, Feb 8, 2013 at 5:17 PM, Joseph Gabriel <string...@gmail.com> wrote:
When activating a view, I'm having trouble getting knockout to find templates by id.  This error occurs when placing the template block anywhere in the same file as the view.  If the template block is placed in the main .cshtml file that is initially loaded, the template works fine.

Does anyone know what may be causing this?  I'm going to look into it over the weekend, but wanted to see if anyone has any ideas.  Hopefully it's just something I'm doing wrong.  Either way, I'll update this thread once I get it solved.

--
You received this message because you are subscribed to the Google Groups "DurandalJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to durandaljs+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Rob Eisenberg,
Blue Spire Consulting, Inc.
Caliburn Project

Joseph Gabriel

unread,
Feb 8, 2013, 5:24:16 PM2/8/13
to duran...@googlegroups.com, Joseph Gabriel, r...@bluespire.com
a knockoutJS native template  (see http://knockoutjs.com/documentation/template-binding.html)

looks like this:

<script type="text/html" id="person-template">
    <h3 data-bind="text: name"></h3>
    <p>Credits: <span data-bind="text: credits"></span></p>
</script>

Rob Eisenberg

unread,
Feb 8, 2013, 8:23:12 PM2/8/13
to Joseph Gabriel, duran...@googlegroups.com
Ah. With Durandal you neither need (or probably want) "native" templates. Durandal's compose binding can do what native templates can do plus much, much more. Have a read through this: https://github.com/BlueSpire/Durandal/wiki/Composition

That said, if you really, really want to define your views that way, you will be able to very soon. I am making some improvements to the view locator and view engine that will allow you to declare views in script tags if you desire. But, it's really not recommended. With Durandal, you can place each view in it's own html file.

Dan Beaulieu

unread,
Feb 11, 2013, 7:02:13 PM2/11/13
to duran...@googlegroups.com, Joseph Gabriel, r...@bluespire.com
As mentioned, I'm experimenting with Durandal's compose binding to display a tree like structure.

Here's a knockout way of achieving this.  (Imagine a models ko observable collection with an item that has properties Id, Name, Children where Children is an instance of the object just described. )
<ul class="nav"  data-bind="template: { name: 'models_template', foreach: models }"></ul>

<script type="text/html" id="categories_template">
    <li class="category_header" data-bind="attr: { id: 'category_' + Id }">
        <span data-bind="text: Name"></span>
        <!-- ko if: HasChildren -->
            <ul data-bind='template: { name: "categories_template", foreach: Children }'>
            </ul>-->
        <!-- /ko -->
    </li>  
</script>

I've working on a Durandal approach but so far only get the following error (obviously I need 

JavaScript runtime error: /App/views/Array.html HTTP status


<table>
    <thead>
        <tr>
            <th>Name</th><th>Model</th>
        </tr>
    </thead>
    <tbody data-bind="foreach: models">
        <tr>
            <td data-bind="text: Name"></td>
            <td data-bind="compose: { model: Children }"></td>
        </tr>        
    </tbody>
</table>

Rob Eisenberg

unread,
Feb 11, 2013, 7:26:23 PM2/11/13
to Dan Beaulieu, duran...@googlegroups.com, Joseph Gabriel
You should use a foreach binding with a compose inside it.

<td data-bind="foreach: Children">
    <!-- ko compose: $data --><!-- /ko-->
</td>

Dan Beaulieu

unread,
Feb 13, 2013, 10:16:00 AM2/13/13
to duran...@googlegroups.com, Dan Beaulieu, Joseph Gabriel, r...@bluespire.com
Thanks for the tip, and kudos to DurandalJS

Here is how i got my recursive tree-like-table to work.  Note the constructor for a model:

var ctor = function (id, name, children) {
        this.id = id;
        this.name = name;
        this.children = { 'models': children };
    };

<table>
    <thead>
        <tr>
            <th style="border:solid">ID</th>
            <th style="border:solid">Name</th>
        </tr>
    </thead>
    <tbody data-bind="foreach: models">
        <tr>
            <td style="border:solid"><label data-bind="text: id"></label><input data-bind="value: name" /> <a>delete</a></td>
            <td style="border:solid"><!-- ko compose: { model:children, view:'views/models/show' } --><!-- /ko--></td>
        </tr>
    </tbody>
</table>

Anitha & Varada T

unread,
Apr 10, 2013, 11:42:47 AM4/10/13
to duran...@googlegroups.com, Joseph Gabriel, r...@bluespire.com
I tried the composition route. Inside the composed view, I had the following piece of html

This item occurred <span data-bind="text: $data.Count()"></span>
<!-- ko if: $data.Count() == 1 -->
    time
<!-- /ko -->
<!-- ko if: $data.Count() != 1 -->
    times
 <!-- /ko -->

the $data.Count() got databound in the span correctly. But the if condition was effectively ignored showing me 

This item occurred 1 time times

Thoughts?

Thanks

madhu

unread,
Apr 10, 2013, 2:05:42 PM4/10/13
to duran...@googlegroups.com, Joseph Gabriel, r...@bluespire.com
Better way to do is compute function and return string depending on count.

Please let me know if it does not work.

Thanks,
Madhu

madhu

unread,
Apr 10, 2013, 4:23:39 PM4/10/13
to duran...@googlegroups.com, Joseph Gabriel, r...@bluespire.com
Please see the below fiddle for knockout template. Write your conditional logic in viewmodels rather than in views.

http://jsfiddle.net/aDYnh/

Not everything can be done with if and ifnot binding as knockout doesnot support if else.

There is one switch case binding in knockout. 


Please let me know if anything.

Thanks,
Madhu

Mike Kidder

unread,
Apr 10, 2013, 5:05:36 PM4/10/13
to duran...@googlegroups.com, Joseph Gabriel, r...@bluespire.com

You can do a ko.computed in your viewModel:

        var myArray = ko.observableArray(['item one','item two', 'item three'])
    
        var totalOccurence = ko.computed(function () {
            var count = myArray().length;
            return count.toString() + (count > 1 ? ' times' : ' time');
        });

And then in your view:

   This item occurred <span data-bind="text: totalOccurence()"></span>


On Wednesday, April 10, 2013 10:42:47 AM UTC-5, Anitha & Varada T wrote:

Anitha & Varada T

unread,
Apr 10, 2013, 10:08:30 PM4/10/13
to duran...@googlegroups.com, Joseph Gabriel, r...@bluespire.com
I understand that there are other ways of accomplishing what I wanted. The example was a trivial one to explain the knockout if, ifnot binding not working inside such a composed view. I am wondering if this is a bug, lack of feature, a by design state etc :)

Thanks,
Varada

madhu

unread,
Apr 10, 2013, 10:27:18 PM4/10/13
to duran...@googlegroups.com, Joseph Gabriel, r...@bluespire.com
I think its not supported in knockout yet.  

Mike Kidder

unread,
Apr 11, 2013, 5:38:55 PM4/11/13
to duran...@googlegroups.com, Joseph Gabriel, r...@bluespire.com
The ko containerless logic does work.  Try  $data.Count == 1 instead.  I just prefer to keep that type logic in viewModel.


On Wednesday, April 10, 2013 10:42:47 AM UTC-5, Anitha & Varada T wrote:

Anitha & Varada T

unread,
Apr 12, 2013, 1:39:33 AM4/12/13
to duran...@googlegroups.com, Joseph Gabriel, r...@bluespire.com
I am probably missing something obvious then. Can you please help me?

Here is the snippet of html that is produced by the composition.

<!-- ko compose: 'item.html'-->
<div class="durandal-wrapper" data-view="views/item" data-active-view="true">
This item occured <span data-bind="text: $data.Count()">1</span>
time
    
times
</div>
<!--/ko-->

Note that the <!-- ko: if: $data.Count --> is effectively absent in the html. I have tried both $data.Count, $data.Count()

Thanks!

Mike Kidder

unread,
Apr 12, 2013, 8:23:45 AM4/12/13
to duran...@googlegroups.com, Joseph Gabriel, r...@bluespire.com
Is Count a property of your data result?  If not, you need to use $data.length to get number of items in array.  Attach a copy of your view and viewModel, and I will take a look.  
You can send directly to "mikekidder AT gmail DOT com"
Reply all
Reply to author
Forward
0 new messages