gpt4 book ai didi

javascript - 从数据绑定(bind)外部引用 knockout 数组并且没有路径知识

转载 作者:行者123 更新时间:2023-12-03 02:39:13 25 4
gpt4 key购买 nike

我在开发网络应用程序时遇到了一些问题。需要从 knockout 外部(或者更确切地说,在 .js 文件中)访问在 foreach 绑定(bind)中使用的 knockout.js 数组。现在,ko.dataFor()ko.contextFor() 允许我访问数组特定元素的上下文和数据,但不能访问数组本身。

我基本上需要的是能够扫描整个数组(所有元素)以获取其中一个属性的值,并在发出请求时通过 AJAX 将所有存在的属性发送到服务器,以便“过滤掉”那些已经存在的,使它成为多个数组条目的唯一选择器,如果这有意义的话。

我很确定答案就在上述函数中的某个地方,但我似乎找不到它。

编辑:

外部脚本需要访问保存用于绑定(bind)的元素的可观察数组,或者了解从 View 模型的根开始到该数组的路径。我无法使用 subscribe 获取数据信息,因为我不知道要订阅什么。模型是动态的,本例中的示例数组即使存在,也会嵌套 3 层。它本身也在循环中,因此它的路径根据访问的 html 元素而变化,例如,它在父循环中的索引可能不同。我唯一的入口点是绑定(bind)的元素。

查看示例以更好地理解。

var VM = {};
var data = {
exampleArray: [{
key: 1,
value: 'foo1'
},
{
key: 2,
value: 'foo2'
},
{
key: 3,
value: 'foo3'
}
],
lookup: [{
key: 1,
value: 'foo1'
},
{
key: 2,
value: 'foo2'
},
{
key: 3,
value: 'foo3'
},
{
key: 4,
value: 'foo4'
},
{
key: 5,
value: 'foo5'
}
]
}

ko.mapping.fromJS(data, {}, VM);
ko.applyBindings(VM);

function addRow() {
var select = document.getElementById('selector');
var value = select.options[select.selectedIndex].value;
var text = select.options[select.selectedIndex].text;
VM.exampleArray.push({
key: ko.observable(value),
value: ko.observable(text),
})
}
#container {
width: 300px;
margin-bottom: 10px;
}

#container>div {
border: solid 1px green;
min-height: 15px;
padding: 3px;
margin: 3px;
}
select {
width: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
<div id="container" data-bind="foreach: exampleArray">
<div>
<span data-bind="text: key() + ' - '"></span>
<span data-bind="text: value"></span>
</div>
</div>
<select id="selector" data-bind="options: lookup,
optionsText: 'value',
optionsValue: 'key'
"></select>
<button onclick="addRow();">Add a row</button>

<p> Now imagine that the lookup data set is updated from the server via AJAX call every time a row is added, where it would need to send only the rows that are not already present in this data set, making this a unique selection. I would need a way to send keys already selected to the server, so that SQL can filter out what data to send back and what data to skip. <br><br>

<b>How would i get this information?</b><br><br>

P.S. I need a way to send an array of keys, not the whole model or data-set or whatever inventive solution might be, because this is an oversimplifed example, the real model is deep nested and much more complex, and pretty much inaccessible/untouchable in the heirarchy of the app's classes that make it. If you need clerification as to why, post a comment and I will try to answer as briefly as possible.</p>

特别编辑:

var VM = {};
var data = {
some: {
super: [
{
deep: {
nested: {
shit: {
articles: [
{key: 1, value: "fish"},
{key: 2, value: "fruit"},
{key: 3, value: "meat"},
],
}
}
}
}
],
lookup: [
{key: 1, value: "fish"},
{key: 2, value: "fruit"},
{key: 3, value: "meat"},
{key: 4, value: "eggs"},
{key: 5, value: "bread"},
{key: 6, value: "milk"},
{key: 7, value: "water"},
]
}
}

ko.mapping.fromJS(data, {}, VM);
ko.applyBindings(VM);

document.getElementById('sayt').addEventListener('focus', function(){
document.getElementById('saytResults').style.display = "block";
})
document.getElementById('sayt').addEventListener('blur', function(){
document.getElementById('saytResults').style.display = "none";
})

function printListItemContextData(btn){
console.log(ko.contextFor(btn.parentNode.getElementsByClassName('selectedArticles')[0].children[0]));
}
#sayt, #saytResults{
width: 200px;
}
#saytResults > div {
border: solid 1px black;
padding: 2px;
width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>

<div data-bind="foreach: some.super">
<div class="selectedArticles" data-bind="foreach: deep.nested.shit.articles">
<div data-bind="text: key() + ' - ' + value()"></div>
</div>
<p>Imagine that the input control below is a "full text search" of the articles on the database. As you type, a request is sent to the server with your typed text as a parameter for the query, results get delivered into the lookup dataset.</p>

<input id="sayt" type="text" value="Click here to simulate request">
<div id="saytResults" style="display: none;" data-bind="foreach: $root.some.lookup">
<div data-bind="text: key() + ' - ' + value()"></div>
</div>
<br>
<p>
The goal however is to NOT display elements that are already present in the dataset. But I cannot get to that data set, I have no idea how to "target" the array. The button below can 'print' the info (console.log) of any of the elements already in the list, but not the list itself.
</p>
<button onclick="printListItemContextData(this)"> PRINT </button>
<p>The issue is, parent context is not created as you go deep down the tree, and $parent of an element of a <b>foreach</b> is not the array it is in, but rather an object, 3 levels up.</p>
</div>

最佳答案

如果您知道您的数据是一个数组,并且该数组的每个元素都有一个子 DOM 节点,则可以通过迭代子节点并从每个子节点获取 dataFor 来重建该数组。附加的代码片段就是这样做的。

更新:调整代码,因此每个元素有多少个子节点并不重要。

var VM = {};
var data = {
some: {
super: [
{
deep: {
nested: {
shit: {
articles: [
{key: 1, value: "fish"},
{key: 2, value: "fruit"},
{key: 3, value: "meat"},
],
}
}
}
}
],
lookup: [
{key: 1, value: "fish"},
{key: 2, value: "fruit"},
{key: 3, value: "meat"},
{key: 4, value: "eggs"},
{key: 5, value: "bread"},
{key: 6, value: "milk"},
{key: 7, value: "water"},
]
}
}

ko.mapping.fromJS(data, {}, VM);
ko.applyBindings(VM);

document.getElementById('sayt').addEventListener('focus', function(){
document.getElementById('saytResults').style.display = "block";
})
document.getElementById('sayt').addEventListener('blur', function(){
document.getElementById('saytResults').style.display = "none";
})

function printListItemContextData(btn){
const el = btn.parentNode.getElementsByClassName('selectedArticles')[0];
const data = [];

for (const c of el.children) {
data[ko.contextFor(c).$index()] = ko.dataFor(c);
}

console.log("Data:", ko.toJS(data));
}
#sayt, #saytResults{
width: 200px;
}
#saytResults > div {
border: solid 1px black;
padding: 2px;
width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>

<div data-bind="foreach: some.super">
<div class="selectedArticles" data-bind="foreach: deep.nested.shit.articles">
<div data-bind="text: key() + ' - ' + value()"></div>
</div>
<p>Imagine that the input control below is a "full text search" of the articles on the database. As you type, a request is sent to the server with your typed text as a parameter for the query, results get delivered into the lookup dataset.</p>

<input id="sayt" type="text" value="Click here to simulate request">
<div id="saytResults" style="display: none;" data-bind="foreach: $root.some.lookup">
<div data-bind="text: key() + ' - ' + value()"></div>
</div>
<br>
<p>
The goal however is to NOT display elements that are already present in the dataset. But I cannot get to that data set, I have no idea how to "target" the array. The button below can 'print' the info (console.log) of any of the elements already in the list, but not the list itself.
</p>
<button onclick="printListItemContextData(this)"> PRINT </button>
<p>The issue is, parent context is not created as you go deep down the tree, and $parent of an element of a <b>foreach</b> is not the array it is in, but rather an object, 3 levels up.</p>
</div>

关于javascript - 从数据绑定(bind)外部引用 knockout 数组并且没有路径知识,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48400487/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com