如何通过按钮切换文本区域的显示,使用带有 foreach 绑定的挖空

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

本文关键字:foreach 绑定 显示 按钮 何通过 文本 区域      更新时间:2023-09-26

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

我希望对此的修复不会太戏剧化,并且涉及对我的代码进行完全返工,因为通过某种魔术,到目前为止,所有其他功能都在工作。我添加了 {attr id: guid}(guid 是从数据库中检索的项目的唯一标识符)语句,试图建立一个唯一的 ID,以便触发正确的控件......虽然这不起作用。

抱歉,我没有工作抖动来显示问题...我试图创建一个,但它没有说明问题。

.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());
        };
    })
};

奇怪的是

data-bind="visible: show"

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

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

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;
}

问题是需要在项目数组中定义可观察show。目前,所有文本区域都在查看相同的可观察量。这意味着您还必须将函数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());
        };
    }
};

可能有一种更干净的方法可以在您的项目中实现这一点,我只是想在不对您提供的代码进行大量更改的情况下展示我的意思。