【问题标题】:Updating a JSTree using Knockout Custom Binding使用 Knockout 自定义绑定更新 JSTree
【发布时间】:2015-05-23 00:21:40
【问题描述】:

我正在尝试创建一个使用 Knockout JS 作为项目视图模型的 JSTree 接口。

我希望能够通过自定义绑定中发生 JSTree“构建”的视图模型创建/重命名/删除节点。我很难弄清楚如何在我的视图模型中访问 jstree(同时保持 ui 解耦),以便我可以 CRUD 节点。

我显然不想将新对象推送到数组中,但这样做是为了证明 observableArray([]) 可用于数据。

http://jsfiddle.net/ascendantofrain/76cco3cs/41/

HTML

<div class="wrapper">

    <div class="button-wrapper">
        <button type="button" class="btn btn-success btn-sm" data-bind="click: $root.createFolder">Create Folder</button>
        <button type="button" class="btn btn-success btn-sm" data-bind="click: $root.createFile">Create File</button>
        <button type="button" class="btn btn-warning btn-sm" data-bind="click: $root.rename">Rename</button>
        <button type="button" class="btn btn-danger btn-sm" data-bind="click: $root.delete">Delete</button>
    </div>
    <pre data-bind="text: treeData"></pre>

    <div id="jstree_demo_div" data-bind="jstree: { data: treeData }"></div>

    <!-- <div id="jstree_demo_dev_attributes">
        <ul>
          <li>Attribute Reporting Group
            <ul>
              <li>Invoice Dates</li>
            </ul>
          </li>
        </ul>
    </div> -->

</div>

淘汰赛 JS

function tree() {
    var self = this;

    self.createFolder = function (data) {
        self.treeData.push({
            'id': 'iPhone',
            'parent': 'device',
            'text': 'iPhone',
            'type': 'default'
        });
    };

    self.createFile = function (data) {
        self.treeData.push({
            'id': 'ios8',
            'parent': 'iPhone',
            'text': 'iOS 8',
            'type': 'file'
        });
    };

    self.rename = function (data) {
    };

    self.delete = function (data) {
    };

    self.treeData = ko.observableArray([
        { 'id': 'animal', 'parent': '#', 'text': 'Animals' },
        { 'id': 'device', 'parent': '#', 'text': 'Devices' },
        { 'id': 'dog', 'parent': 'animal', 'text': 'Dogs' }
    ]);
};

ko.bindingHandlers.jstree = {
    buildTree: function (element, treeData) {
        $(element).jstree('destroy');
        $(element).jstree({
            'core': {
                'animation': 0,
                'check_callback': true,
                'data': treeData
            },
            'types': {
                '#': {
                    'max_depth': 4,
                    'valid_children': ['root']
                },
                'level_1': {
                    'valid_children': ['default']
                },
                'level_2': {
                    'valid_children': ['file']
                },
                'file': {
                    'icon': 'glyphicon glyphicon-file'
                }
            },
            'plugins': [
                'search',
                'state',
                'types',
                'wholerow',
                'unique'
            ]
        });
    },
    update: function (element, valueAccessor) {
        var treeData = ko.unwrap(valueAccessor());
        ko.bindingHandlers.jstree.buildTree(element, treeData.data());
    }
};

ko.applyBindings(new tree());

【问题讨论】:

    标签: javascript jquery mvvm knockout.js jstree


    【解决方案1】:

    为时已晚,但请看一下:http://jsfiddle.net/u4a7k5zu/20/

    这是你的小提琴的修改版本。不确定这是否是您要找的。不过,您可能已经想通了。也许它可以帮助其他人。

    小提琴代码:

    function tree() {
    var self = this;
    
    //display actions in fiddle
    self.consoleLine = "<p class=\"console-line\"></p>";
    self.consoleLog = function (text) {
        $("#console-log").append($(self.consoleLine).html(text));
    };
    self.clearConsoleLog = function () {
        $("#console-log").html('');
    };
    
    
    self.tree = $('#jstree_demo_div'); //get jstree div
    self.isNodeSelected = ko.observable(false);
    self.selectedNode = ko.observable({});
    
    //deselect all nodes
    self.deselectAllNodes = function () {
        self.tree.jstree('deselect_all');
    }
    
    //keep track of selected node
    self.tree.on("changed.jstree", function (e, data) {
        var node = self.tree.jstree().get_selected(true)[0]; //get current selected node
        if (typeof node !== 'undefined') {
            self.isNodeSelected(true);
            self.selectedNode(node);
            self.consoleLog('selected node id: ' + node.id + ', type: ' + node.type);
        } else {
            self.isNodeSelected(false);
        }
    });
    
    self.createFolderNode = function (data) {
        //node can be created on a preselected node or pass # to create a root node
        var node;
        var data;
        if (self.isNodeSelected()) 
        {
            node = self.selectedNode();
            data = {'id': Math.floor((Math.random() * 10000) + 1),
                        'text': 'iPhone', 'type': 'folder'};
        } 
        else
        {
            node = '#';
            data = {'id': Math.floor((Math.random() * 100000) + 1),
                    'parent': '#',
                    'text': 'New Root Node',
                    'type' : 'root'
                     };            
        }
        //create node
        var id = self.tree.jstree("create_node", node, data, 'last');
        self.tree.jstree('open_node', node);
        self.tree.jstree('edit', id);
    
    };
    
    self.createFileNode = function (data) {
        //Below code only allows files to be created within folders.
        //Structure it as per createFolder method to create files at root
        var data = {
            'id': Math.floor((Math.random() * 100000) + 1),
                'text': 'iOS 8',
                'type': 'file'
        }
        //create file node
        var id = self.tree.jstree("create_node", self.selectedNode(), data, 'last');
        self.tree.jstree('open_node', self.selectedNode());
        self.tree.jstree('edit', id);
    };
    
    self.renameNode = function (data) {
        if(self.isNodeSelected()){
            self.tree.jstree('edit', self.selectedNode());
        }
        else{
            alert('please select a node to rename!');
        }
    };
    
    self.deleteNode = function (data) {
        if(self.isNodeSelected()){
            self.tree.jstree('delete_node', self.selectedNode());
        }
        else{
            alert('please select a node to delete!');
        }
    };
    
    self.treeData = ko.observableArray([{
        'id': 1,
            'parent': '#',
            'text': 'Animals',
        'type': '#'
    }, {
        'id': 2,
            'parent': '#',
            'text': 'Devices',
            'type' : '#'
    }, {
        'id': 'dog',
            'parent': 1,
            'text': 'Dogs',
            'type' : 'folder'
    }]);
    };
    
    ko.bindingHandlers.jstree = {
    buildTree: function (element, treeData) {
        $(element).jstree('destroy');
        $(element).jstree({
            'core': {
                'animation': 0,
                    'check_callback': true,
                    'data': treeData
            },
                'types': {
                '#': {
                    'max_children': 10,
                    'max_depth': 10,
                    'valid_children': ['root', 'folder','file']
                },
                    'folder': {
                    'valid_children': ['folder','file']
                },
                    'file': {
                        'icon': 'glyphicon glyphicon-file',
                        'max_depth': 0
                }
            },
                'plugins': [
                'search',
                'state',
                'types',
                'wholerow']
        });
    },
    update: function (element, valueAccessor) {
        var treeData = ko.unwrap(valueAccessor());
        ko.bindingHandlers.jstree.buildTree(element, treeData.data());
    }
    };
    
    ko.applyBindings(new tree());
    

    【讨论】:

    • 谢谢队友 :) 这在一定程度上帮助了我......真的很感激。一个问题;我们如何集成拖放功能,以便我们可以将文件夹和/或文件拖动到其他文件夹?另一个问题,假设我们有 2 个从服务器提取的 JSON 文件,一个用于文件夹,一个用于文件,那么我们如何在用户没有意识到的情况下无缝保存更改?非常感谢
    • @Farzad,拖放功能可作为 jstree 上的插件使用。
    • @Farzad,第一个问题:请参阅jstree plugin 页面了解如何包含它。第二个问题:我不确定我是否理解这个问题。从服务器拉取或保存到服务器或通知用户更改?你能澄清你的第二个问题吗? here 涵盖了使用 json 填充 jstree。另一个this useful link (although quite old)。抱歉回复晚了,我还没来!
    • 非常感谢你,伙计,这真的很有帮助 :) 真的很感激,干杯 :) 第二个问题;好吧,我的意思是如何让 JSON 数据始终保持同步……所以如果重命名了 FILE 并且更改了其父级,则视图会无缝更改,如果您要刷新页面,结果将是同样,所以我想每次发生更改时都会发送/接收一个ajax请求......对!谢谢
    • @Farzad,是的,每次修改 jstree 节点时都必须发出 ajax get/post 请求。不过,必须小心处理 ajax 更新失败。如果 ajax 请求失败,那么只需刷新 jstree,它将用旧数据重新填充自己,假设您在第一个实例中使用 json 填充它。在这种情况下,状态插件很有用,因为刷新 jstree 会恢复其状态,无论是修改还是未修改。
    猜你喜欢
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    • 2014-09-13
    • 1970-01-01
    • 2015-09-08
    • 2014-06-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多