Help with Click & Visible Binding for Multiple divs

105 views
Skip to first unread message

gsr...@gmail.com

unread,
Mar 18, 2013, 3:37:30 PM3/18/13
to knock...@googlegroups.com
Hello.  I'm fairly new to knockout and am trying to figure something out (which is probably pretty straight forward for someone who knows knockout better).  I've searched around and haven't been able to find an adequate solution, so I thought I'd post the question(s) here.

I have a view that contains multiple divs, and each div has an <a> tag to open (make visible) and close (make not visible) a small configuration section.  I used knockout's click and visible bindings to handle the clicking of the <a> tag and showing/hiding the configuration div.  Here's a couple snippets:

                <div>
                   
<div>
                        header1
                       
<a data-bind="click: toggleConfiguration" href="javascript:;" title="configure"></a>
                   
</div>
                   
<div>
                       
<div data-bind='visible: displayConfiguration'>
                           
<span>number of items to retrieve</span>
                           
<input id="numberOfItemsToRetrieve1" type="text" data-bind="value: numberOfItemsToRetrieve1, valueUpdate: 'afterkeydown'" placeholder="a number between 1 and 20" />
                       
</div>
                       
<div>
                            details1
                       
</div>
                   
</div>
               
</div>

               
<div>
                   
<div>
                        header2
                       
<a data-bind="click: toggleConfiguration" href="javascript:;" title="configure"></a>
                   
</div>
                   
<div>
                       
<div data-bind='visible: displayConfiguration'>
                           
<span>number of items to retrieve</span>
                           
<input id="numberOfItemsToRetrieve2" type="text" data-bind="value: numberOfItemsToRetrieve2, valueUpdate: 'afterkeydown'" placeholder="a number between 1 and 20" />
                       
</div>
                       
<div>
                            details2
                       
</div>
                   
</div>
               
</div>
               
                ...


            displayConfiguration = ko.observable(false),
            toggleConfiguration = function() {
                if (displayConfiguration())
                    displayConfiguration(false);
                else
                    displayConfiguration(true);
                return false;
            },



The problem is that I click one div's <a> tag, it opens all divs' configuration divs.  I need it to only make visible the configuration div of the containing div.  For example, if I click header1's <a>, it should only open/close the configuration div above details1.

Can anyone help me with this?  Do I have to create some sort of custom binding to handle this?  And, if so, how?  Or, do I need to not use knockout and just use jQuery directly?

Thanks!

aureli...@gmail.com

unread,
Mar 18, 2013, 11:05:07 PM3/18/13
to knock...@googlegroups.com, gsr...@gmail.com
It's because both div's, header1 and header2, are using the same displayConfiguration 

You should have only one for div

What do you thing about?

function ConfigOneViewModel(){
displayConfiguration = ko.observable(false),
toggleConfiguration = function() {
if (displayConfiguration())
displayConfiguration(false);
else
displayConfiguration(true);
return false;
}

function ConfigTwoViewModel(){
displayConfiguration = ko.observable(false),
toggleConfiguration = function() {
if (displayConfiguration())
displayConfiguration(false);
else
displayConfiguration(true);
return false;
}

ko.applyBindings(new ConfigOneViewModel(),document.getElementById("configOne"));
ko.applyBindings(new ConfigOneViewModel(),document.getElementById("configTwo"));

<div id="configOne">
<div>
header1
<a data-bind="click: toggleConfiguration" href="javascript:;" title="configure"></a>
</div>
....
</div>

<div id="configTwo">
<div>
header2
<a data-bind="click: toggleConfiguration" href="javascript:;" title="configure"></a>
</div>
....
</div>

gsr...@gmail.com

unread,
Mar 18, 2013, 11:20:26 PM3/18/13
to knock...@googlegroups.com, gsr...@gmail.com, aureli...@gmail.com
Hi.  Thanks for writing back and offering up a solution.  I thought of something similar to what you've suggested.  The problem is that I'll have more than two divs that have this structure and need this functionality.  I'll have more like 16 on the same page.  So, I was looking for some programmatic way of handling all of the divs and not re-writing the same code 16 times.

Any suggestions?

Anyone?

Denys Khanzhiyev

unread,
Mar 19, 2013, 4:23:48 AM3/19/13
to knockoutjs
Open loops for yourself:

function ConfigViewModel(){
      
this.displayConfiguration = ko.observable(false),
this.toggleConfiguration = function() {
if (this.displayConfiguration())
this.displayConfiguration(false);
else
this.displayConfiguration(true);
return false;
}

vm = {};
for(var i = 0; i<16; i++){
  vm['ConfigView'+i] = new ConfigViewModel();
}
ko.applyBindings(vm);

<div data-bind='with: ConfigView0'>

                   
<div>
                        header1
                       
<a data-bind="click: toggleConfiguration" href="javascript:;" title="configure"></a>
                   
</div>
                   
<div>
                       
<div data-bind='visible: displayConfiguration'>
                           
<span>number of items to retrieve</span>
                           
<input id="numberOfItemsToRetrieve1" type="text" data-bind="value: numberOfItemsToRetrieve1, valueUpdate: 'afterkeydown'" placeholder="a number between 1 and 20" />
                       
</div>
                       
<div>
                            details1
                       
</div>
                   
</div>
               
</div>
<div data-bind='with: ConfigView1'>

                   
<div>
                        header2
                       
<a data-bind="click: toggleConfiguration" href="javascript:;" title="configure"></a>
                   
</div>
                   
<div>
                       
<div data-bind='visible: displayConfiguration'>
                           
<span>number of items to retrieve</span>
                           
<input id="numberOfItemsToRetrieve2" type="text" data-bind="value: numberOfItemsToRetrieve2, valueUpdate: 'afterkeydown'" placeholder="a number between 1 and 20" />
                       
</div>
                       
<div>
                            details2
                       
</div>
                   
</div>
               
</div>
....
But this is bad practice. Consider building your DOM from viewmodel with template:

function ConfigViewModel(settings){
        this.header = settings.header;
        this.label = settings.label || 'number of items to retrieve';
        this.numberOfItemsToRetrieve2 = ko.observable(settings.initialValie);
        this.details = settings.details;
        this.afterkeydown = function(){....}

this.displayConfiguration = ko.observable(false),
this.toggleConfiguration = function() {
if (this.displayConfiguration())
this.displayConfiguration(false);
else
this.displayConfiguration(true);
return false;
}

var data = [
  {
     header: 'Header 1',
     initialValue: '',
     details: 'Details 1'
  },
  {
     header: 'Header 2',
     initialValue: '',
     label: 'non standart label',
     details: 'Details 2'
  },
   ...
]

vm = {
   items: ko.observableArray();
   fillData: function(adata){
        this.items(adata.map(function(dataItem){
           return new ConfigViewModel(dataItem);
        });
   }
}
vm.fillData(data);
ko.applyBindings(vm);

and markup;

<div data-bind='foreach: items'>
   <div>
                   
<div>
                       <span data-bind='text: header'><span>
                       
<a data-bind="click: toggleConfiguration" href="javascript:;" title="configure"></a>

                   
</div>
                   
<div>
                       
<div data-bind='visible: displayConfiguration'>

                           
<span data-bind='text:label'></span>
                           
<input id="numberOfItemsToRetrieve2" type="text" data-bind="value: numberOfItemsToRetrieve, valueUpdate: 'afterkeydown'" placeholder="a number between 1 and 20" />
                       
</div>
                       
<div data-bind='text:details'>
                            details2
                       
</div>
                   
</div>
               
</div>
</div>


2013/3/19 <gsr...@gmail.com>
--
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.
 
 

Reply all
Reply to author
Forward
0 new messages