praveensewak
praveensewak

Reputation: 114

knockoutjs radio button checked value with protectedobservable

thank you for looking into this.

I have the following example built: http://jsfiddle.net/zm381qjx/5/

This is a menu list builder. When you add a menu, an edit form pops up. Using protectedObservable so that i can either commit or reset (as per code). One functionality, which i am having problems with, is there is radio button list (for TypeId), and depending on the value (10 = Url, 20 = Category, 30 = Page), you set the respective properties (10 = Url, 20 = CategoryId, 30 = PageId).

Flicking through the radio buttons, if Url is selected, another textbox should show (based on urlVisible) so user can enter the Url. I have added a span with text: TypeId.temp so i can see the temporary value. This is very irregular. Try to flick through several times.

Any help will be greatly appreciated.

My HTML

<a class="btn btn-primary" data-bind="click: addMenu">Add Menu</a>
<ul data-bind="foreach: Menus">
    <li><a href="#" data-bind="text: Name, click: editMenu"></a></li>
</ul>
<div class="panel panel-default" data-bind="slideIn: editMenuItem, with: editMenuItem">
    <div class="panel-body">
        <div class="form-group">
            <label for="MenuName">Name: </label>
            <input type="text" id="MenuName" data-bind="value: Name" class="form-control" />
        </div>
        <label class="radio-inline">
            <input type="radio" name="MenuTypeId" value="10" data-bind="checked: TypeId" /> Url
        </label>
        <label class="radio-inline">
            <input type="radio" name="MenuTypeId" value="20" data-bind="checked: TypeId" /> Category
        </label>
        <label class="radio-inline">
            <input type="radio" name="MenuTypeId" value="30" data-bind="checked: TypeId" /> Page
        </label>
        <div class="form-group" data-bind="visible: urlVisible">
            <label for="MenuUrl">Url: </label>
            <input type="text" id="MenuUrl" data-bind="value: Url" class="form-control" />
        </div>
        <br />
        <p>TypeId.temp = <span data-bind="text: TypeId.temp"></span></p>
        <br /><br />
        <input type="button" class="btn btn-success" value="Update" data-bind="click: commit" /> or 
        <a href="#" data-bind="click: reset">Cancel</a>
    </div>
</div>

My JS:

var vm = null;

//wrapper for an observable that protects value until committed
ko.protectedObservable = function (initialValue) {
    //private variables
    var _temp = ko.observable(initialValue);
    var _actual = ko.observable(initialValue);

    var result = ko.dependentObservable({
        read: function () {
            return _actual();
        },
        write: function (newValue) {
            _temp(newValue);
        }
    });

    //commit the temporary value to our observable, if it is different
    result.commit = function () {
        var temp = _temp();
        if (temp !== _actual()) {
            _actual(temp);
        }
    };

    //notify subscribers to update their value with the original
    result.reset = function () {
        _actual.valueHasMutated();
        _temp(_actual());
    };

    result.temp = _temp;

    return result;
};

ko.bindingHandlers.slideIn = {
    init: function (element) {
        $(element).hide();
    },
    update: function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        if (value) {
            $(element).stop().hide().slideDown('fast');
        } else {
            $(element).stop().slideUp('fast');
        }
    }
};

var Menu = function (Id, Name, TypeId, CategoryId, PageId, Url) {
    var self = this;

    /* Core Properties */
    self.Id = ko.observable(Id);
    self.Name = ko.protectedObservable(Name);
    self.TypeId = ko.protectedObservable(TypeId);
    self.CategoryId = ko.protectedObservable(CategoryId);
    self.PageId = ko.protectedObservable(PageId);
    self.Url = ko.protectedObservable(Url);

    /* Virtual Properties */
    self.urlVisible = ko.computed(function () {
        return self.TypeId.temp() == "10";
    }, self);


    /* Virtual Functions */
    self.editMenu = function (data) {
        if(vm.editMenuItem()) {
            vm.editMenuItem(null);
        }
        vm.editMenuItem(data);
    };

    /* Core Functions */
    self.commit = function () {
        if (self.Name.temp() == '' || self.Name.temp() == null) {
            alert('Please enter a name.'); return;
        }

        self.Name.commit();
        self.TypeId.commit();
        self.CategoryId.commit();
        self.PageId.commit();
        self.Url.commit();

        vm.editMenuItem(null);
    };
    self.reset = function () {
        self.Name.reset();
        self.TypeId.reset();
        self.CategoryId.reset();
        self.PageId.reset();
        self.Url.reset();

        vm.editMenuItem(null);
    };
};

var ViewModel = function() {
    var self = this;

    /* Core Properties */
    self.Menus = ko.observableArray([]);

    /* Virtual Properties */
    self.editMenuItem = ko.observable(null);
    self.addMenu = function(){
        var menu = new Menu(0, "New Menu", "10", 0, 0, "");
        self.Menus.push(menu);
        self.editMenuItem(menu);
    };
};


$(function () {
    vm = new ViewModel();
    ko.applyBindings(vm);
});

Upvotes: 0

Views: 682

Answers (1)

Rohith Nair
Rohith Nair

Reputation: 1070

If you change your radio button binding to

<input type="radio" name="MenuTypeId" value="10" data-bind="checked: TypeId.temp" />

The temp id will be changed accordingly and radio button behaviour is consistent, but not with TypeId as value.

also the protectedObservable binding the radio button value is not playing nice

When you manually click the radio the TypeId value is never changed (as you are not committing the value) and I guess that as the radio button value never changes from 10 , it is not recognizing the subsequent manual clicks on Url radio button.

I updated the value using a button and it is changing accordingly; but then it will not move the value from that TypeId on subsequent radio button clicks

And the problem is still appearing for protectedObservable binding but not with a simple observable.

Code which explores this idea further: http://jsfiddle.net/zm381qjx/101/

Upvotes: 1

Related Questions