使用Knockout Custom Binding更新JSTree

时间:2015-03-19 18:19:13

标签: javascript jquery mvvm knockout.js jstree

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

我希望能够通过viewmodel创建/重命名/删除节点,其中JSTree'building'在自定义绑定中发生。我很难弄清楚如何在我的viewmodel中访问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>

KNOCKOUT 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());

1 个答案:

答案 0 :(得分:6)

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

这是你小提琴的修改版。不确定这是否是你要找的。你可能已经弄明白了。也许它可以帮助别人。

FIDDLE CODE:

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());