简体   繁体   中英

Knockout.js Change (not toggle) css class on click

I'm trying to manipulate of css class on knockout.js click event, but it's not working. Currently I'm binding css class basing on value of $data.IsSelected element (true | false). I can't get what is right way to do what I want - should I manipulate with DOM (as I'm trying to do now) or should I change value of observableArray element to be true instead of false, for example and then update ViewModel, so theoretically this must change css class. Here is JS.

<script>
        function StyleViewModel() {
            var self = this;
            self.pref = ko.observableArray();
            self.img = ko.observableArray(["img/style1.png", "img/style2.png", "img/style3.png", "img/style4.png", "img/style5.png", "img/style6.png"]);
            self.toggle = function (data, event) {
                if (data.IsSelected == true) {  
                    //Here i'm trying to manipulate with DOM directly                 
                    $(event.target).closest("div").removeClass("txt-active").addClass("txt");
                    $(event.target).find("a.button").text("Добавить");
                }
                else {                 
                    $(event.target).removeClass("txt").addClass("txt-active");
                    $(event.target).find("div.txt-active > a.button").text("Добавлено");
                }
            }
            $.getJSON('/api/usersprofiles?userguid=' + $("#MainContent_guid").val(), self.pref);
        }
        $(document).ready(function () {
            ko.applyBindings(new StyleViewModel());
            $("#go").click(function () {
                $("div.test-block").each(function () {
                    var style = $(this).find("h3").text();
                    var option = $(this).find("a").text();
                    var selected;
                    if (option == "Добавить") {
                        selected = false;
                    }
                    else if (option == "Добавлено") {
                        selected = true;
                    }
                    var json = "{'UserGUID':'" + $("#MainContent_guid").val() + "', 'Style':'" + style + "', 'Selected':'" + selected + "'}"
                    $.ajax({
                        type: "POST",
                        dataType: "json",
                        contentType: 'application/json; charset=utf-8',
                        url: "/api/usersprofiles",
                        data: json,
                        success: function () { },
                        error: function (xhr, status, error) {
                            var err = eval("(" + xhr.responseText + ")");
                            alert(err.Message);
                        }
                    });
                });
                setTimeout(function () {
                    window.location.replace("default.aspx");
                }, 3000);
            });
        });
    </script>

And this it HTML to show binding:

<input type="hidden" runat="server" id="guid" />
    <div class="container">
        <div class="title">
            <h2>Вкусы</h2>
            <p>Что вам по душе?</p>
        </div>
        <div class="styles" data-bind="foreach: pref">
            <div class="test-block" data-bind="click: $root.toggle">
                <input type="hidden" data-bind="value: $data.Id" />
                <div class="bigshadowtest">
                    <img alt="" src="img/bigshadow.png">
                </div>
                <div data-bind="css: $data.IsSelected == true ? 'txt-active' : 'txt'">
                    <h3 data-bind="text: $data.name"></h3>
                    <a href="#" class="button" data-bind="text: $data.IsSelected == true ? 'Добавлено' : 'Добавить'"></a>
                </div>
                <img alt="" data-bind="attr: { src: $root.img }">
            </div>
        </div>
        <table class="info" style="width: 100%; height: 100%;">
            <tr>
                <td style="text-align: center; vertical-align: middle;">
                    <a href="#" id="go" class="gobtn">Поехали!</a>
                </td>
            </tr>
        </table>
    </div>

PS Here is one more problem - I can't bind observableArray self.img to the corresponding img element.

Make your observable array's elements observable. With mapping plugin , so that your isSelected will be an observable and reflects it's value change to the ui.

Change your getJson method (untested code)


$.getJSON('/api/usersprofiles?userguid=' + $("#MainContent_guid").val(), function(data) {
    ko.mapping.fromJS(data, self.pref);
});

Or instead of using the mapping plugin u can create a new pref object and bind the data from server to that in a loop and push them into the observableArray. This way is more controllable then using mapping plugin.

    var oPref = function (data) {
        var self = this;

        self.Id = ko.observable(data.Id);
        self.IsSelected = ko.observable(data.IsSelected);
        self.name = ko.observable(data.name);
        self.imgLink = ko.observable(data.imgLink);

        self.toggle = function () {
            if (self.IsSelected()) self.IsSelected(false);
            else self.IsSelected(true);
        }
    }

        function StyleViewModel() {
            var dataFromServer = [ 
                { Id: 1, IsSelected: false, name: "name1", imgLink: "img/style1.png" },
                { Id: 2, IsSelected: false, name: "name2", imgLink: "img/style2.png" },
                 { Id: 3, IsSelected: false, name: "name3", imgLink: "img/style3.png" }]

            var self = this;

            self.pref = ko.observableArray();

            ko.utils.arrayForEach(dataFromServer, function(item) { self.pref.push(new oPref(item)); });
        }
    $(document).ready(function () {
        ko.applyBindings(new StyleViewModel());
    });

And your html should be like follows

<input type="hidden" runat="server" id="guid" />
<div class="container">
    <div class="title">
         <h2>Вкусы</h2>

        <p>Что вам по душе?</p>
    </div>
    <div class="styles" data-bind="foreach: pref">
        <div class="test-block" data-bind="click: toggle">
            <input type="hidden" data-bind="value: Id" />
            <div class="bigshadowtest">
                <img alt="" src="img/bigshadow.png">
            </div>
            <div data-bind="css: { 'txt-active': IsSelected(), 'txt': IsSelected() == false }">
                 <h3 data-bind="text: name"></h3>
 <a href="#" class="button" data-bind="text: (IsSelected() == true ? 'Добавлено' : 'Добавить')"></a>

            </div>
            <img alt="" data-bind="attr: { src: imgLink }">
        </div>
    </div>
    <table class="info" style="width: 100%; height: 100%;">
        <tr>
            <td style="text-align: center; vertical-align: middle;"> <a href="#" id="go" class="gobtn">Поехали!</a>

            </td>
        </tr>
    </table>
</div>

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