Сохранение данных json в jstree через обратную передачу через asp:hiddenfield

Я изливал это часами, и мне еще предстоит продвинуться вперед, поэтому я надеялся, что один из замечательных обитателей SO сможет мне помочь. Вот проблема...

Я реализую дерево через плагин jstree для jQuery. Я извлекаю данные, которыми я программно заполняю дерево, из нашего веб-приложения через json, сброшенный в asp: HiddenField, в основном так:

JavaScriptSerializer serializer = new JavaScriptSerializer();
string json = serializer.Serialize(Items);

json = json.ToLower();
data.Value = json;    

Затем дерево извлекает json из скрытого поля, чтобы построить себя. Это прекрасно работает до тех пор, пока я не попытаюсь сохранить данные, для которых выбраны/открыты узлы. Чтобы упростить мою проблему, я жестко закодировал некоторые данные json в дерево и попытался использовать плагин cookie для сохранения данных состояния дерева. Это не работает по какой-либо причине. Я видел другие проблемы, когда людям нужно загружать плагины в определенном порядке и т. Д., Это не решило мою проблему. Я попробовал ту же настройку с html_data, и она отлично работает. С этим работающим постоянством я преобразовал плагин cookie для сохранения данных в другом asp:hiddenfield (мы не можем использовать файлы cookie для этого типа вещей в нашем приложении).

по сути, операции с файлами cookie идентичны, он просто сохраняет массив узлов как значение скрытого поля. Это работает с html_data, но не с json, и мне еще предстоит указать, где он терпит неудачу.

Это замена jQuery.cookie.js:

jQuery.persist = function(name, value) {
    if (typeof value != 'undefined') { // name and value given, set persist
        if (value === null) {
            value = '';
        }
        jQuery('#' + name).attr('value', value);
    } else { // only name given, get value
        var persistValue = null;
        persistValue = jQuery('#' + name).attr('value');
        return persistValue;
    }
};

Код jstree.cookie.js идентичен, за исключением нескольких изменений имени переменной. А это мое дерево:

$(function() {
                $("#demo1").jstree({
                    "json_data": {
                        "data" : [
                        {
                            "data" : "A node",
                            "children" : [ "Child 1", "Child 2" ]
                        },
                        {
                            "attr": { "id": "li.node.id" },
                            "data" : {
                                "title": "li.node.id",
                                "attr": { "href": "#" }
                            },
                            "children": ["Child 1", "Child 2"]
                        }
                    ]
                    },
                    "persistence": {
                        "save_opened": "<%= open.ClientID %>",
                        "save_selected": "<%= select.ClientID %>",
                        "auto_save": true
                    },
                   "plugins": ["themes", "ui", "persistence", "json_data"]
                });
            });

Данные хранятся в скрытых полях надлежащим образом, проблема возникает при обратной передаче, узлы не открываются повторно. Любая помощь будет принята с благодарностью.

Просмотрев это еще немного, я просто хотел объяснить, что мне кажется, что проблема в том, что дерево еще не было построено из JSON_data, когда предпринимаются попытки операций сохранения. Есть ли способ отложить эти действия до полной загрузки дерева?


person Keener    schedule 02.09.2010    source источник


Ответы (2)


Если кто-то все еще пытается выполнить тот же тип операции с jsTree версии 3.0+, есть более простой способ выполнить тот же тип функциональности, не редактируя какой-либо из основных JavaScript jsTree и не полагаясь на плагин «состояние» ( Версия 1.0 - "Постоянство"):

var jsTreeControl = $("#jsTreeControl");
//Can be a "asp:HiddenField"
var stateJSONControl = $("#stateJSONControl");
var url = "exampleURL";

jsTreeControl.jstree({
    'core': {
        "data": function (node, cb) {
            var thisVar = this;

            //On the initial load, if the "state" already exists in the hidden value 
            //then simply use that rather than make a AJAX call
            if (stateJSONControl.val() !== "" && node.id === "#") {
                cb.call(thisVar, { d: JSON.parse(stateJSONControl.val()) });
            }
            else {
                $.ajax({
                    type: "POST",
                    url: url,
                    async: true,
                    success: function (json) {
                        cb.call(thisVar, json);
                    },
                    contentType: "application/json; charset=utf-8",
                    dataType: "json"
                }).responseText;
            }
        }
    }
});

//If the user changes the jsTree, save the full JSON of the jsTree into the hidden value, 
//this will then be restored on postback by the "data" function in the jsTree decleration
jsTreeControl.on("changed.jstree", function (e, data) {
    if (typeof (data.node) != 'undefined') {
        stateJSONControl.val(JSON.stringify(jsTreeControl.jstree(true).get_json()));
    }
});

Этот код создаст jsTree и сохранит его «состояние» в скрытом значении, а затем при обратной передаче, когда jsTree воссоздается, он будет использовать свое старое «состояние», восстановленное из «HiddenField», вместо того, чтобы делать новый вызов AJAX и терять расширения/выборы, сделанные пользователем.

person David Rogers    schedule 26.02.2016

Получил правильную работу с данными JSON. Мне пришлось отредактировать функции «повторно открыть» и «повторно выбрать» внутри самой jstree.

Вот новая функционирующая функция повторного открытия для всех, кто в ней нуждается.

reopen: function(is_callback) {
                var _this = this,
                    done = true,
                    current = [],
                    remaining = [];
                if (!is_callback) { this.data.core.reopen = false; this.data.core.refreshing = true; }
                if (this.data.core.to_open.length) {
                    $.each(this.data.core.to_open, function(i, val) {
                        val = val.replace(/^#/, "")
                        if (val == "#") { return true; }
                        if ($(("li[id=" + val + "]")).length && $(("li[id=" + val + "]")).is(".jstree-closed")) { current.push($(("li[id=" + val + "]"))); }
                        else { remaining.push(val); }
                    });
                    if (current.length) {
                        this.data.core.to_open = remaining;
                        $.each(current, function(i, val) {
                            _this.open_node(val, function() { _this.reopen(true); }, true);
                        });
                        done = false;
                    }
                }
                if (done) {
                    // TODO: find a more elegant approach to syncronizing returning requests
                    if (this.data.core.reopen) { clearTimeout(this.data.core.reopen); }
                    this.data.core.reopen = setTimeout(function() { _this.__callback({}, _this); }, 50);
                    this.data.core.refreshing = false;
                }
            },

The problem was that it was trying to find the

  • element by a custom attribute. It was just pushing these strings into the array to search when it was expecting node objects. Using this line

    if ($(("li[id=" + val + "]")).length && $(("li[id=" + val + "]")).is(".jstree-closed")) { current.push($(("li[id=" + val + "]"))); }
    

    вместо

    if ($(val).length && $(val).is(".jstree-closed")) { current.push(val); }
    

    было все, что нужно. Используя аналогичный процесс, я также смог сохранить выбранные узлы таким образом.

    Надеюсь, это поможет кому-то.

    person Keener    schedule 03.09.2010