Template reset or reload

145 views
Skip to first unread message

jjf...@gmail.com

unread,
May 31, 2013, 11:23:05 AM5/31/13
to knock...@googlegroups.com
Hello,
How can I force my templates to reset or reload (by clicking on their links: Employees | Departments )?
<div id="subhead">
   
<span id="header">Master/Detail with nested viewmodels</span><br>
<a href="#" data-bind="click:function() {setModule('EmployeesTemplate',employeesVM)}">Employees</a> |
<a href="#" data-bind="click:function() {setModule('DepartmentsTemplate',employeesVM)}">Departments</a>
<hr></div>
<div id="mainContainer" data-bind="template:myModule"></div>


Here's a fiddle: http://jsfiddle.net/jjfrick/D2GPT/

Ryan Rahlf

unread,
Jun 1, 2013, 5:56:05 PM6/1/13
to knock...@googlegroups.com
Hi JJ.

Thanks for posting the fiddle.  Clearing your selected employee is not too difficult to accomplish, and it's an opportunity to kill to birds with one stone, in this case.

Aside from helping you clear the selected employee, I'd like to recommend a small "best practice" change to your code which would probably have made the solution to your question a lot more evident.  Here's the item in question:

<a href="#" data-bind="click:function() {setModule('EmployeesTemplate',employeesVM)}">Employees</a>

You've written your click event handler right into your data-bind statement.  That is, you've written *logic* in your *html*.  It's considered a best-practice to keep all your logic in your code (js, view models, or support libraries), your structure in your HTML, and your style in your CSS.  When they mix, things start getting more difficult, which is what you're running in to here.  In the case of the code you posted, you've got a couple options to get that function out of your data-bind declaration:

*****Option One*******
Create a click handler for each menu item as a function of your view model.  For example:

var viewModel = {
    showEmployees : function(){ setModule('EmployeesTemplate',employeesVM); },
    showDepartments : function(){ setModule('DepartmentsTemplate',employeesVM); },
    ...
}

and then your binding becomes simply:

<a href="#" data-bind="click:showEmployees">Employees</a>
<a href="#" data-bind="click:showDepartments">Departments</a>

This is the most straightforward way to get the click handlers out of the binding declaration, but we can go a step farther.

******Option Two*******
Turn the menu itself into an observable array and display it with knockout.  

When knockout calls a click handler, it supplies the data item as the first parameter and the DOM event object as the second parameter.  This allows you to handle all menu clicks with the same click handler, which continues to optimize your code against the DRY principal (Don't Repeat Yourself).

var viewModel = {
    ....
    menu : new ko.observableArray([
        {name: 'Employees', template : 'EmployeesTemplate'},
        {name: 'Departments', template : 'DepartmentsTemplate'}
    ]),
    menuItemClicked : function(dataItem, event){
        var name = dataItem.name; 
        var template = dataItem.template;
        setModule(template, this.employeesVM);
    },
    ....
}

and then bind the menu with a foreach

<div id="subhead">
    <span id="header">Master/Detail with nested viewmodels</span><br/>
    <!-- ko foreach: menu -->
        <a href="#" data-bind="click:$parent.menuItemClicked, text:name"></a> |        
    <!-- /ko -->
    <hr/>
</div>

*****Clearing the View******

So, back to your original question; how do you reset the state of your view when a link is clicked?  Well, now that your click handlers are easily accessable, it's a snap.  Let's say you went with option two above.  All you need to do is create a function that resets your view state and call it somewhere from within your click handler.

var viewModel = {
    ...
    resetState : function(){
        this.myModule({});
        this.employeesVM.selectedEmployee(),//clear selected employee
        this.employeesVM.selectedDepartment(),//clear selected department
        this.employeesVM.searchTerm(),
        this.employeesVM.setDepartment(),
this.employeesVM.getEmployees(),
this.employeesVM.getEmpDetails()
        //whatever else needs to be reset to blank
    },
    menuItemClicked: function(dataItem, event){
        this.resetState();
        ...//the rest from above
    },
    ...
}

I hope this helps!

-Ryan Rahlf
______________________________
Sign up for my newsletter for more tips and tricks 



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

jjf...@gmail.com

unread,
Jun 4, 2013, 8:44:15 AM6/4/13
to knock...@googlegroups.com
Hi Ryan, Thank you very much for you acute response. I have tried both options and I get "ReferenceError: setModule is not defined" on each one:
Option 1, Option 2

I'm also looking for examples that use something similar to the setModule function and the bootstrap - tabs approach.

Ryan Rahlf

unread,
Jun 6, 2013, 10:11:45 AM6/6/13
to knock...@googlegroups.com

Hi JJ,

The issue you're running into now is a scope problem.  Inside your "menuItemClicked" method you're running in window scope (global scope), not the scope of your view model, which means that "this" isn't pointing to what you'd expect.  

You could use the "self" closure pattern to fix this, and I've written up a blog post to help anyone else who might run into this.  You can read that post here : http://ryanrahlf.com/knockout-js-why-we-use-self-or-how-to-fix-referenceerror-xyz-is-not-defined/

I'm going to be writing up a free "Knockout - getting started guide" which will go over this and a few more issues that seem to crop up a lot when starting out with Knockout.  Sign up for my newsletter and you'll be sure to get that when it comes out in the next couple weeks!

-Ryan Rahlf
_____________________
@Ryanthem

rpn

unread,
Jun 6, 2013, 10:19:30 AM6/6/13
to knock...@googlegroups.com
Just wanted to mention that when using the click/event bindings, Knockout executes the handler with the context (this) set to the current data rather than the window object.  The main time that you will run into issues with context is when calling functions from a different scope ($root, $parent, $parents[1]).

Ryan Rahlf

unread,
Jun 6, 2013, 10:28:42 AM6/6/13
to knock...@googlegroups.com
Thanks for the clarification Ryan, I'll update my post!

Ryan Rahlf

unread,
Jun 6, 2013, 10:51:55 AM6/6/13
to knock...@googlegroups.com
Thanks again for the correction Ryan.  I've updated my post, and I owe you a beer.

-Ryan Rahlf


On Thursday, June 6, 2013 9:19:30 AM UTC-5, rpn wrote:

jjf...@gmail.com

unread,
Jun 6, 2013, 11:05:00 AM6/6/13
to knock...@googlegroups.com, jjf...@gmail.com
Thanks Ryan and rpn, I had a feeling it was a scope issue. I would really like to see a fiddle that can demonstrate this and hopefully I can share one once I figure this out. I have been fiddling with a couple of yours rpn: http://jsfiddle.net/rniemeyer/Ujr4z/ and http://jsfiddle.net/rniemeyer/xVxKD/

What I'm shooting for is to do the something like the following within a tab or menu item click like the fiddles mentioned above.
<div data-bind="foreach: departments()">
 
<h2 data-bind="text: DeptName"></h2>
   
<!-- ko foreach: $root.empForDept(DeptID) -->
     
<strong>
       
<a href="#" data-bind="click: $root.selectedEmployee">  
         
<span class='employees' data-bind="text: Name"></span>
       
</a>
       
<span data-bind="visible: $root.selectedEmployee()===$data">
         
<br><span class='details'>Phone: <span data-bind='text: Phone' ></span></span>            
       
</span>
     
</strong>&nbsp;&nbsp;<br>
   
<!-- /ko -->
</div>

Here that fiddle: http://jsfiddle.net/jjfrick/BDqXP/

Ryan R. I look forward to your "getting started guide" I will definitely check it out.

And one again, I know I sound like a broken record but I truly appreciate all those who take the time to share. I would think the approach I'm shooting for would be fairly common place and many newbies like myself could learn from it.



Reply all
Reply to author
Forward
0 new messages