为“关联数组”创建新的kendo绑定

时间:2014-07-15 19:15:39

标签: kendo-ui

我首先要说的是我根本不知道这是否可行,但我正在阅读Kendo UI文档,并试图找出如何至少尝试一下,但是我在制作自定义绑定时遇到了很多困难。这是我仍在处理的另一个问题的后续问题,该问题已发布here。如果这不是一个合适的问题,请告诉我,我会将其关闭或改写​​。在这一点上,我真的很迷茫和迷茫。

根据我的理解,基于我被告知和尝试的内容,剑道无法绑定到关联数组,不是因为数据不好,而是因为它是一组对象,每个都作为一个单独的单独实体 - 在正常情况下,数组会有所不同,并包含长度属性,以及其他一些函数 array 原型,可以通过它进行迭代。

所以我试图猜想如何解决这个问题。我成功地获得了认为的功能解决方法。我作为"思考"因为我对Javascript的经验太缺,无法真正了解这样做的后果(性能,稳定性等)

这就是我的所作所为;

剑道模板

<script type="text/x-kendo-template" id="display-items-many">
        # for(var key in data) { #
        #   if (data.hasOwnProperty(key) && data[key].hasOwnProperty("Id")) { #
        <tr>
            <td>
                <strong>#= data[key].Id #</strong>
            </td>
            <td class="text-right">
                <code>#= data[key].Total #</code>
            </td>
        </tr>
        #   } #
        # } #
</script>

HTML

<table class="table borderless table-hover table-condensed" data-bind="source: Associative  data-template="display-items-many">

</table>

现在对我来说,立即离开,这给了我运作的幻觉。所以我想更多地考虑如何解决这个问题......

我想创建一个名为binding的新repeat。此绑定的目标如下;

  

为给定根对象中符合给定条件的对象的每个实例重复模板

在我的脑海中,这将起到这样的作用;

<div data-template="repeater-sample" data-bind="repeat: Associative"></div>

<script type="text/x-kendo-template" id="repeater-sample">
   <div> ${ data.Id }</div>
</script>

条件将是一个简称为 _associationKey 的属性。因此,从理论上讲,以下内容将起作用。

$.ajax({
   // get data from server and such.
}).done(function(results){
   // simple reference to the 'associative array' for easier to read code
   var associative = results.AssociativeArray;

   // this is a trait that everything in the 'associative array' should have to match
   // this is purely, purely an example. Obviously you would use a more robust property
   var match = "Id"; 

   // go through the results and wire up the associative array objects
   for(var key in associative ) {
      if(associative.hasOwnProperty(key) && associative[key].hasOwnProperty(match)) {
         associative[key]._associationKey = 10; // obviously an example value
      }
   }

   // a watered down example implementation, obviously a real use would be more verbose
   viewModel = kendo.observable({
      // property = results.property
      // property = results.property
      associativeArray = associative
   });

   kendo.bind('body', viewModel);
});

到目前为止,这实际上似乎工作得很好,但我必须使用内联脚本来硬编码模板中的逻辑。这就是我想要避免的。

问题

最大的问题是我对telerik的自定义绑定文档(可用here)感到非常困惑。我确实有他们的例子可以借鉴,是的 - 但是我对它如何与对象进行交互有点困惑。我会尝试来解释,但我很失落,可能很难。

这就是telerik为示例自定义绑定提供的内容,并且我已经对空间问题进行了一些修剪;

<script>
    kendo.data.binders.repeater = kendo.data.Binder.extend({
        init: function(element, bindings, options) {
            //call the base constructor
            kendo.data.Binder.fn.init.call(this, element, bindings, options);

            var that = this;
            // how do we interact with the data that was bound?
        }
    });
</script>

基本上就是我迷失的地方。我有一个很大的脱节,弄清楚如何与实际的##;关联数组进行交互&#34;使用data-bind="repeat: associativeArray"

绑定的

所以......

  • 我需要与绑定数据进行交互(整个&#39;关联数组&#39;)
  • 我需要告诉它为每个匹配
  • 的实例呈现目标模板

进一步更新

我一直在挖掘剑道源代码,这就是我到目前为止 - 以source绑定为例......但我还是没有得到正确的结果。不幸的是,这会带来一些问题;

  1. 某些功能是kendo的内部功能,我不知道如何在不重写的情况下访问它们。虽然我有源并可以做到这一点,但我更喜欢制作与版本无关的代码,以便它可以插入&#34;插入&#34;到较新的版本

  2. 我完全迷失了很多这样做的事情。我基本上制作了source绑定的副本,并尽可能用我自己的语法替换它,因为这个概念基本上是相同的。 我无法弄清楚测试在哪里进行资格审核,如果有意义的话。

  3. 我在这里有一个很大的逻辑断开 - 理想情况下应该一些的地方我基本上可以说... If the current item that kendo is attempting to render in a template matches a criteria, render it. If not, pass it over 然后另一个地方,我告诉它迭代关联数组中的每个对象&#39;以便达到我测试的程度。

    我觉得强迫for循环在这里实际上会让这个火太多次了,而且我很迷茫。非常感谢任何帮助。

    kendo.data.binders.repeat = kendo.data.Binder.extend({
        init: function(element, bindings, options) {
            kendo.data.Binder.fn.init.call(this, element, bindings, options);
    
            var source = this.bindings.repeat.get();
    
            if (source instanceof kendo.data.DataSource && options.autoBind !== false) {
                source.fetch();
            }
        },
    
        refresh: function(e) {
            var that = this,
                source = that.bindings.repeat.get();
    
            if (source instanceof kendo.data.ObservableArray|| source instanceof kendo.data.DataSource) {
                e = e || {};
    
                if (e.action == "add") {
                    that.add(e.index, e.items);
                } else if (e.action == "remove") {
                    that.remove(e.index, e.items);
                } else if (e.action != "itemchange") {
                    that.render();
                }
            } else {
                that.render();
            }
        },
    
        container: function() {
            var element = this.element;
    
            if (element.nodeName.toLowerCase() == "table") {
                if (!element.tBodies[0]) {
                    element.appendChild(document.createElement("tbody"));
                }
                element = element.tBodies[0];
            }
    
            return element;
        },
    
        template: function() {
            var options = this.options,
                template = options.template,
                nodeName = this.container().nodeName.toLowerCase();
    
            if (!template) {
                if (nodeName == "select") {
                    if (options.valueField || options.textField) {
                        template = kendo.format('<option value="#:{0}#">#:{1}#</option>',
                            options.valueField || options.textField, options.textField || options.valueField);
                    } else {
                        template = "<option>#:data#</option>";
                    }
                } else if (nodeName == "tbody") {
                    template = "<tr><td>#:data#</td></tr>";
                } else if (nodeName == "ul" || nodeName == "ol") {
                    template = "<li>#:data#</li>";
                } else {
                    template = "#:data#";
                }
    
                template = kendo.template(template);
            }
    
            return template;
        },
    
        add: function(index, items) {
            var element = this.container(),
                parents,
                idx,
                length,
                child,
                clone = element.cloneNode(false),
                reference = element.children[index];
    
            $(clone).html(kendo.render(this.template(), items));
    
            if (clone.children.length) {
                parents = this.bindings.repeat._parents();
    
                for (idx = 0, length = items.length; idx < length; idx++) {
                    child = clone.children[0];
                    element.insertBefore(child, reference || null);
                    bindElement(child, items[idx], this.options.roles, [items[idx]].concat(parents));
                }
            }
        },
    
        remove: function(index, items) {
            var idx, element = this.container();
    
            for (idx = 0; idx < items.length; idx++) {
                var child = element.children[index];
                unbindElementTree(child);
                element.removeChild(child);
            }
        },
    
        render: function() {
            var source = this.bindings.repeat.get(),
                parents,
                idx,
                length,
                element = this.container(),
                template = this.template();
    
            if (source instanceof kendo.data.DataSource) {
                source = source.view();
            }
    
            if (!(source instanceof kendo.data.ObservableArray) && toString.call(source) !== "[object Array]") {
                source = [source];
            }
    
            if (this.bindings.template) {
                unbindElementChildren(element);
    
                $(element).html(this.bindings.template.render(source));
    
                if (element.children.length) {
                    parents = this.bindings.repeat._parents();
    
                    for (idx = 0, length = source.length; idx < length; idx++) {
                        bindElement(element.children[idx], source[idx], this.options.roles, [source[idx]].concat(parents));
                    }
                }
            }
            else {
                $(element).html(kendo.render(template, source));
            }
        }
    });
    

1 个答案:

答案 0 :(得分:2)

我建议在associative array中将传输array转换为更简单的解决方案。这非常简单(对大多数情况而言)可以解决您的问题。

假设您从服务器收到以下关联数组:

{
    "One" : { Name: "One", Id: "id/one" },
    "Two" : { Name: "Two", Id: "id/two" },
    "Three" : { Name: "Three", Id: "id/three" }
}

这是存储在名为input的变量中。将其从associative转换为无关联就像以下一样简单:

var output = [];
$.each(input, function(idx, elem) {
    elem.index = idx;
    output.push(elem);
});

现在,您在output中有一个等效数组,我将索引字段保存到一个名为index的字段中,用于关联数组的每个元素。

现在,您可以使用开箱即用的代码显示从服务器收到的数据。

在此处查看此行动:http://jsfiddle.net/OnaBai/AGfWc/

您甚至可以使用KendoUI DataSource来使用DataSource.schema.parse方法检索和转换数据:

var dataSource = new kendo.data.DataSource({
    transport: {
        read: ...
    },
    schema : {
        parse: function (response) {
            var output = [];
            $.each(response, function(idx, elem) {
                elem.index = idx;
                output.push(elem);
            });
            return output;
        }
    }
});

你的模型将是:

var viewModel = new kendo.data.ObservableObject({
    Id: "test/id",
    Associative: dataSource
});

您可以在此处看到它:http://jsfiddle.net/OnaBai/AGfWc/1/