如何使用带有 foreach 绑定的敲除通过按钮切换文本区域的显示?

How can I toggle the display of a textarea via a button using knockout with the foreach binding?

我是淘汰赛新手。对于我的问题,我试图让每个项目都有一个按钮和文本区域。文本区域将在页面加载时隐藏。如果我单击该按钮,它将显示文本区域(切换)。目前,如果我点击按钮,页面上的所有文本区域都会显示,而不仅仅是相应的文本区域。

我希望对此的修复不会太过戏剧化,并且涉及对我的代码进行彻底的修改,就像一些魔法一样,到目前为止所有其他功能都可以正常工作。我添加了 {attr id: guid}(guid 是从数据库中检索到的项目的唯一标识符)语句,试图建立一个唯一的 ID,以便触发正确的控件……尽管这不起作用。

抱歉,我没有可用的 jfiddle 来说明问题...我尝试创建一个,但它没有说明问题。

JS:

 //if a cookie exists, extract the data and bind the page with cookie data
    if (getCookie('filterCookie')) {
        filterCookie = getCookie('filterCookie');
        var cookieArray = filterCookie.split(",");
        console.log(cookieArray);

        $(function () {
            var checkboxes = new Array();
            for (var i = 0; i < cookieArray.length; i++) {
                console.log(i + cookieArray[i]);
                checkboxes.push(getCheckboxByValue(cookieArray[i]));
                //checkboxes.push(document.querySelectorAll('input[value="' + cookieArray[i] + '"]'));
                console.log(checkboxes);
                checkboxes[i].checked = true;
            }
        })

        filterCookie = getCookie('filterResultsCookie');
        cookieArray = filterCookie.split(",");
        filterCookieObj = {};
        filterCookieObj.action = "updateProjects";
        filterCookieObj.list = cookieArray;
        $.ajax("/api/project/", {
            type: "POST",
            data: JSON.stringify(filterCookieObj)
        }).done(function (response) {


            proj = response;
            ko.cleanNode(c2[0]);
            c2.html(original);
            ko.applyBindings(new ProjectViewModel(proj), c2[0]);

        });
    }

//if the cookie doesn't exist, just bind the page
    else {
        $.ajax("/api/project/", {
            type: "POST",
            data: JSON.stringify({
                action: "getProjects"
            })
        }).done(function (response) {
            proj = response;
            ko.cleanNode(c2[0]);
            c2.html(original);
            ko.applyBindings(new ProjectViewModel(proj), c2[0]);

        });
    }

查看模型:

function ProjectViewModel(proj) {
            //console.log(proj);
            var self = this;
            self.projects = ko.observableArray(proj);
            self.show = ko.observable(false);
            self.toggleTextArea = function () {
                self.show(!self.show());
            };
        };

HTML:

                <!-- ko foreach: projects -->
            <div id="eachOppyProject" style="border-bottom: 1px solid #eee;">
            <table>
                <tbody>
                    <tr>
                        <td><a data-bind="attr: { href: '/tools/oppy/' + guid }" style="font-size: 25px;"><span class="link" data-bind="    value: guid, text: name"></span></a></td>
                    </tr>
                    <tr data-bind="text: projectDescription"></tr>
<%--                    <tr data-bind="text: guid"></tr>--%>
                </tbody>
            </table>
                 <span class="forminputtitle">Have you done project this before?</span>  <input type="button" value="Yes" data-bind="click: $parent.toggleTextArea" class="btnOppy"/>
                <textarea placeholder="Tell us a little of what you've done." data-bind="visible: $parent.show, attr: {'id': guid }" class="form-control newSessionAnalyst" style="height:75px; " /><br />
                <span> <input type="checkbox" name="oppyDoProjectAgain" style="padding-top:10px; padding-right:20px;">I'm thinking about doing this again. </span>
            <br />
                </div><br />
                <!-- /ko -->

斯宾塞:

function ProjectViewModel(proj) {
    //console.log(proj);
    var self = this;
    self.projects = ko.observableArray(proj);
    self.projects().forEach(function() { //also tried proj.forEach(function())
        self.projects().showComments = ko.observable(false);
        self.projects().toggleComments = function () {
            self.showComments(!self.showComments());
        };
    })
};

问题是 show observable 需要在 projects 数组中定义。目前,所有文本区域都在查看相同的可观察对象。这意味着您还必须将函数 showTextArea 移动到项目数组中。

您可能还需要考虑重命名您的函数或完全删除它。暗示它们直接将更改驱动到视图的函数名称与 MVVM 模式背道而驰。我建议使用 "toggleComments" 这样的名称,因为它不引用视图控件。

编辑:

举个例子:

function ProjectViewModel(proj) {
    //console.log(proj);
    var self = this;
    self.projects = ko.observableArray(proj);
    foreach(var project in self.projects()) {
        project.showComments = ko.observable(false);
        project.toggleComments = function () {
            self.showComments(!self.showComments());
        };
    }
};

在您的项目中可能有更简洁的方法来实现它我只是想展示我的意思,而不会对您提供的代码进行大量更改。

奇怪的是

data-bind="visible: show"

不提供任何绑定错误,因为 ko foreach 中的绑定上下文:项目是项目而不是 ProjectViewModel。

无论如何,这个解决方案应该可以解决您的问题:

function ViewModel() {
    var self = this;
    var wrappedProjects = proj.map(function(p) {
        return new Project(p);
    });
    self.projects = ko.observableArray(wrappedProjects);
}

function Project(proj) {
   var self = proj;   
   self.show = ko.observable(false);
   self.toggleTextArea = function () {
       self.show(!self.show());
   }
   return self;
}