简体   繁体   中英

Knockout toggle active class on click

I have a knockout app and within it I have a function which shows/hides elements on the page depending on the selected option. The button that has been selected to activate a particular toggle will have an 'active' class so that it 'stands out' from the others and is clearly visible that that's the selected option. My problem is that I've created a knockout function to toggle the active class but it's triggering the active state on all of the buttons rather than the selected button and I'm not sure why?

var viewModel = function(){
    var self = this;
    self.isActive = ko.observable(false);
    self.toggleActive = function(data, event){
        self.isActive(!self.isActive()); //toggle the isActive value between true/false
    }
}

<button data-bind="click: toggleActive, css : {'activeStyle' : isActive}">Toggle Active</button>
<button data-bind="click: toggleActive, css : {'activeStyle' : isActive}">Toggle Active</button>
<button data-bind="click: toggleActive, css : {'activeStyle' : isActive}">Toggle Active</button>

Fiddle: http://jsfiddle.net/amMup/5/

You only have one viewmodel for all three buttons. That means you only have a single "isActive" flag that all buttons are bound to.

Instead, use an array of items and a foreach loop to render each one. Here's a tweaked version of your view model:

var viewModel = function(){
    var self = this;
    self.items = [
        { isActive: ko.observable(false) },
        { isActive: ko.observable(false) },
        { isActive: ko.observable(false) }
        ];
    self.toggleActive = function(data, event){
        data.isActive(!data.isActive());//toggle the isActive value between true/false
    }
}

var myModel = new viewModel();

ko.applyBindings(myModel);

And the HTML is simplified:

<div data-bind="foreach: items">
    <button data-bind="click: $parent.toggleActive, css : {'activeStyle' : isActive}">Toggle Active</button>
</div>

Note the use of $parent to access the parent's binding context . When you're inside a foreach loop, the binding context is the individual item pulled from the foreach loop. By accessing $parent you "reach up" to the object that contains the items property -- which, in your case, is the viewmodel where the toggleActive exists.

Here's an updated fiddle: http://jsfiddle.net/psteele/amMup/6/

This is because you have them all bound to the same observable.

http://jsfiddle.net/Kohan/fdzqJ/

Js

var viewModel = function(){
    var self = this;
    self.isActive1 = ko.observable(false);
    self.isActive2 = ko.observable(false);
    self.isActive3 = ko.observable(false);

    self.toggleActive = function(data){
        data(!data());
    }
}

var myModel = new viewModel();

ko.applyBindings(myModel);

HTML

<button data-bind="click: function(){toggleActive(isActive1)}, css : {'activeStyle' : isActive1}">Toggle Active</button>
<button data-bind="click: function(){toggleActive(isActive2)}, css : {'activeStyle' : isActive2}">Toggle Active</button>
<button data-bind="click: function(){toggleActive(isActive3)}, css : {'activeStyle' : isActive3}">Toggle Active</button>

Another way:

<button data-bind="click: function(){setActive('1')}, css:  buttonActive() == '1' ? 'active' : '' ">Toggle Active</button>

var viewModel = function(){
    var self = this;
    self.buttonActive = ko.observable(false);
    self.buttonActive = function(index){
        self.buttonActive(index);
    }
}

var myModel = new viewModel();

ko.applyBindings(myModel);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM