hotdiggity
hotdiggity

Reputation: 329

Tricky toggling in KnockoutJS

Have a drill down form field with fields progressively appearing. While I've figured out the logic for making them appear one-at-a-time down the page, including a simple toggle, the issue is resetting all observables to their original state when "No" is clicked (and with all fields clearing). Currently if "Yes" is clicked a second time (after completing the form, then deciding "No") all the fields reappear at once instead of progressively. http://jsfiddle.net/hotdiggity/JJ6f6/

Knockout model:

var ViewModel = function () {
    var self = this;
    self.showField1 = ko.observable(true);
    self.showField2 = ko.observable(false);
    self.showField3 = ko.observable(false);
    self.showField4 = ko.observable(false);
    self.yesOrNo = ko.observable("");
    self.hasValue = ko.observable("");
    self.toggleCalc = ko.observable("");

    self.showField2 = ko.computed(function () {
        return self.yesOrNo() == 'yes';
    });

    self.showField3 = ko.computed(function () {
        self.showField4(false);           
        return ( !! self.hasValue());
    });

    self.toggleCalc = function () {
        self.showField4(!self.showField4());
    };

};

ko.bindingHandlers.fadeVisible = {
    init: function (element, valueAccessor) {
        var value = valueAccessor();
        $(element).toggle(ko.utils.unwrapObservable(value));
    },
    update: function (element, valueAccessor) {
        var value = valueAccessor();
        ko.utils.unwrapObservable(value) ? $(element).fadeIn() : $(element).fadeOut();
    }
};

ko.applyBindings(new ViewModel());

HTML:

<div class='list-inputs'>
     <h2>Drilldown toggle interaction</h2>
    <!--LEVEL 1-->
    <div data-bind='fadeVisible: showField1'>(L1) Choose one to display more options:
        <p>
            <label>
                <input type='radio' name="type" value='yes' data-bind='checked: yesOrNo' />Yes</label>
            <label>
                <input type='radio' name="type" value='no' data-bind='checked: yesOrNo' />No</label>
        </p>
        <!--LEVEL 2-->
        <div data-bind='fadeVisible: showField2'>
            <p>(L2) Enter input and click off:
                <input type="text" data-bind='value: hasValue' />
            </p>
            <!--LEVEL 3-->
            <div data-bind='fadeVisible: showField3'>
                <p><span>(L3) Earnings:</span>
                    <input type="text" /> <a data-bind="click: toggleCalc" href="#">Toggle calculator</a>
                </p>
                <!--LEVEL 4-->
                <div data-bind='fadeVisible: showField4'>
                    <br />
                    <p><b>(L4) Calculator</b>
                    </p>
                    <p><span>Input 1:</span>
                       <input type="text" />
                    </p>
                    <p><span>Input 2:</span>
                        <input type="text" />
                    </p>
                    <p><span><b>Total:</b></span>
                        <input type="text" />
                    </p>
                </div>
            </div>
        </div>
    </div>
</div>

Upvotes: 0

Views: 145

Answers (1)

PatrickSteele
PatrickSteele

Reputation: 14677

I got this working (I think the way you want) by making two changes:

  • I initialized the yesOrNo field to "no".

  • Changed showField2 to clear out the value of the "L2" textbox whenever the user changes their L1 response to "No". This causes the form to "re-initialize" so the next time they select yes, it will start clean.

    self.showField2 = ko.computed(function () {
        var isNo = self.yesOrNo() == 'no';
        if( isNo )
        {
            self.hasValue('');
        }
        return !isNo;
    });
    

Upvotes: 1

Related Questions