如何使用带有 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;
}
我是淘汰赛新手。对于我的问题,我试图让每个项目都有一个按钮和文本区域。文本区域将在页面加载时隐藏。如果我单击该按钮,它将显示文本区域(切换)。目前,如果我点击按钮,页面上的所有文本区域都会显示,而不仅仅是相应的文本区域。
我希望对此的修复不会太过戏剧化,并且涉及对我的代码进行彻底的修改,就像一些魔法一样,到目前为止所有其他功能都可以正常工作。我添加了 {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;
}