jQuery UI Widgets Forums Navigation Tree jqxTree Load on Demand with Ajax: re-open issue

This topic contains 17 replies, has 8 voices, and was last updated by  Todor 1 year, 3 months ago.

Viewing 15 posts - 1 through 15 (of 18 total)
  • Author

  • Rene Lanz
    Member

    Hello,

    in your example source code of jqxTree in chapter Load on Demand with Ajax, the function that is bound to the expand event returns immediately if the event’s element is the root element:

    if (tree.jqxTree('getItem', event.args.element).label == "Root")
        return

    This prevents the view from repeatedly appending “Root Folder” children.

    But assume your ajax.htm would look like this:

    [
    { "label": "Folder 1", "items": [{ "value": "ajax.html", "label" : "Loading..." } ] },
    { "label": "Folder 2", "items": [{ "value": "ajax.html", "label" : "Loading..." } ] },
    { "label": "Folder 3", "items": [{ "value": "ajax.html", "label" : "Loading..." } ] }
    ]

    Now children will repeatedly be appended when reopening a parent and there is (of course) no static approach anymore.

    I am looking for a pattern to solve the Reopen problem. The server is stateless so I need to make the loading decision in the client.

    Do you have any suggestion/ideas?

    Best regards,
    Rene

    • This topic was modified 7 years, 6 months ago by  Rene Lanz.
    • This topic was modified 7 years, 6 months ago by  Rene Lanz.
    • This topic was modified 7 years, 6 months ago by  Rene Lanz.
    • This topic was modified 7 years, 6 months ago by  Peter Stoev. Reason: Moved to Tree Forum
    • This topic was modified 7 years, 6 months ago by  Rene Lanz.
    • This topic was modified 7 years, 6 months ago by  Rene Lanz.

    Dimitar
    Participant

    Hello Rene,

    Here is a modified version of the demo Load on Demand with Ajax.

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <title id='Description'>This sample demonstrates how to load Tree Items via Ajax
    </title>
    <link rel="stylesheet" href="../../jqwidgets/styles/jqx.base.css" type="text/css" />
    <script type="text/javascript" src="../../scripts/gettheme.js"></script>
    <script type="text/javascript" src="../../scripts/jquery-1.8.2.min.js"></script>
    <script type="text/javascript" src="../../jqwidgets/jqxcore.js"></script>
    <script type="text/javascript" src="../../jqwidgets/jqxbuttons.js"></script>
    <script type="text/javascript" src="../../jqwidgets/jqxscrollbar.js"></script>
    <script type="text/javascript" src="../../jqwidgets/jqxpanel.js"></script>
    <script type="text/javascript" src="../../jqwidgets/jqxtree.js"></script>
    <script type="text/javascript" src="../../jqwidgets/jqxexpander.js"></script>
    <script type="text/javascript">
    $(document).ready(function () {
    var theme = getTheme();
    // Create jqxTree
    var tree = $('#jqxTree');
    var source = [{ label: "Root", expanded: true,
    items: [
    { label: "Root Folder 1", items: [{ value: "ajax1.htm", label: 'Loading...'}] },
    { label: "Root Folder 2", items: [{ value: "ajax2.htm", label: 'Loading...'}] }
    ]
    }];
    tree.jqxTree({ source: source, theme: theme, width: 200 });
    tree.bind('expand', function (event) {
    var label = tree.jqxTree('getItem', event.args.element).label;
    var $element = $(event.args.element);
    var loader = false;
    var loaderItem = null;
    var children = $element.find('ul:first').children();
    $.each(children, function () {
    var item = tree.jqxTree('getItem', this);
    if (item && item.label == 'Loading...') {
    loaderItem = item;
    loader = true;
    return false
    };
    });
    if (loader) {
    $.ajax({
    url: loaderItem.value,
    success: function (data, status, xhr) {
    var items = jQuery.parseJSON(data);
    tree.jqxTree('addTo', items, $element[0]);
    tree.jqxTree('removeItem', loaderItem.element);
    }
    });
    }
    });
    });
    </script>
    </head>
    <body class='default'>
    <div id="jqxTree">
    </div>
    </body>
    </html>

    And here are the files:

    ajax1.htm:

    [
    { "label": "Folder 1", "items": [{ "value": "ajax.htm", "label" : "Loading..." } ] },
    { "label": "Folder 2", "items": [{ "value": "ajax.htm", "label" : "Loading..." } ] },
    { "label": "Folder 3", "items": [{ "value": "ajax.htm", "label" : "Loading..." } ] }
    ]

    ajax2.htm:

    [
    {"label": "Folder 5" },
    {"label": "Folder 6" },
    {"label": "Folder 7" },
    {"label": "Folder 8" }
    ]

    ajax.htm:

    [
    {"label": "Folder 9" },
    {"label": "Folder 10" },
    {"label": "Folder 11" },
    {"label": "Folder 12" }
    ]

    Best Regards,
    Dimitar

    jQWidgets team
    http://www.jqwidgets.com/


    Rene Lanz
    Member

    Hi Dimitar

    Thank you. That was quick. And it works.

    Your code relies on a change of type of element e in tree.jqxTree(‘getItem’, e);
    First call: HTMLLIELement that represents a tree item => ajax()
    Second call: HTMLDivElement => no ajax()

    I rewrote the bind function as follows:

    tree.bind(‘expand’, function(event) {
    var parEl = event.args.element;
    var $parEl = $(parEl);

    var childEl = $parEl.find(‘ul:first’).children();
    var $childEl = $(childEl);

    // First call: HTMLLIELement that represents a tree item => ajax()
    // Second call: HTMLDivElement => return
    if (!tree.jqxTree(‘getItem’, $childEl[0])) {
    return;
    }

    var parItem = tree.jqxTree(‘getItem’, parEl)
    var parLabel = parItem.label;
    $.ajax({
    url: ‘edtree_expand’,
    data: {‘parent’: parLabel},
    success: function (data, status, xhr) {
    var items = jQuery.parseJSON(data);
    tree.jqxTree(‘addTo’, items, $parEl[0]);
    tree.jqxTree(‘removeItem’, $childEl[0]);
    }
    });

    return true;
    });

    However, the fact that I can rely on the fact the *all* labels in my tree are different allows the following:

    tree.bind(‘expand’, function(event) {
    var parEl = event.args.element;
    var $parEl = $(parEl);
    var childEl = $parEl.find(‘li’);
    var $childEl = $(childEl);

    var firstChildItem = tree.jqxTree(‘getItem’, $childEl[0]);
    if (firstChildItem.label != loadingLabel.label)
    return; // already loaded

    var parItem = tree.jqxTree(‘getItem’, parEl);

    $.ajax({
    url : ‘edtree_expand’,
    data: {‘parent’: parItem.label},
    success : function(jsonData, status, xhr) {
    tree.jqxTree(‘removeItem’, $childEl[0]);

    var childItems = jQuery.parseJSON(jsonData);

    // time to render in jqxTree addTo is a problem:
    tree.jqxTree(‘addTo’, childItems, parEl);
    }
    });
    return true;
    });

    Don’t know what I prefer. Anyway, my issue is solved. Thanks again!

    Best regards,
    René


    yehezqiel
    Member

    Hi Peter and Rene.. I also want to load child with ajax for level 2 node.. I’ve try code above but children in level 2 already expanded when I expand level 1 node..

    I’ve also got error like this in firebug :

    I can not post image here…
    The error is like this :
    TypeError: o is undefined on jqxtree.js (line 7)

    Is jqxtree.js must be modified too ?
    thx..

    • This reply was modified 7 years, 5 months ago by  yehezqiel.
    • This reply was modified 7 years, 5 months ago by  yehezqiel.
    • This reply was modified 7 years, 5 months ago by  yehezqiel. Reason: want to show image
    • This reply was modified 7 years, 5 months ago by  yehezqiel.

    yehezqiel
    Member

    can somebody help me please… i’m so confused…


    yehezqiel
    Member

    I got an error in _refreshMapping when calling function _refreshMapping:function(f,q){
    TypeError: o is undefined.

    in that function, i see var o has been initialized with var o=h[k.id];
    but when I show the value of h[k.id], the value has a undefined value..


    Dimitar
    Participant

    Hello yehezqiel,

    Do you experience the issue by running the code we provided or is it your own solution? In the latter case, please post a code sample, which we may test locally.

    Best Regards,
    Dimitar

    jQWidgets team
    http://www.jqwidgets.com/


    yehezqiel
    Member

    Thx for your response Dimitar..
    I use code that you provided in documentation with a little modified by me.
    But I don’t modified source code in jqxtree.js.
    In firebug, there is an error there..

    Here is my code. I want to show a tree with 3 level.. Level 2 will be loaded by ajax when I expand or check node in level 1. And level 3 will be loaded when I expand or check node in level 2.. But level 3 has already loaded when I expand or check node in level 1.
    I’ve try code which is posted by you Dimitar, but doesn’t work for me.

    Here is the JSP file.

    <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <link rel="stylesheet" href="../includes/css/jqxTree/jqx.base.css" type="text/css" />
    <script type="text/javascript" src="../includes/js/jqxTree/gettheme.js"></script>
    <script type="text/javascript" src="../includes/js/jqxTree/jquery-1.8.2.min.js"></script>
    <script type="text/javascript" src="../includes/js/jqxTree/jqxcore.js"></script>
    <script type="text/javascript" src="../includes/js/jqxTree/jqxbuttons.js"></script>
    <script type="text/javascript" src="../includes/js/jqxTree/jqxscrollbar.js"></script>
    <script type="text/javascript" src="../includes/js/jqxTree/jqxpanel.js"></script>
    <script type="text/javascript" src="../includes/js/jqxTree/jqxtree.js"></script>
    <script type="text/javascript" src="../includes/js/jqxTree/jqxexpander.js"></script>
    <script type="text/javascript" src="../includes/js/jqxTree/jqxcheckbox.js"></script>
    <script type="text/javascript" src="../js/common.js"></script>
    <script type="text/javascript">
    $(document).ready(function () {
    var theme = getDemoTheme();
    var tree = $('#jqxTree');
    $('#jqxTree').jqxTree({
    checkboxes: true
    });
    var source = [{
    label: "All Category",
    expanded: true,
    value:"0",
    id:"parent",
    level:"0",
    checked:true,
    items: ${level1}
    }];
    tree.jqxTree({ source: source, theme: theme, width: 600 });
    tree.on('expand', function (event) {
    if (tree.jqxTree('getItem', event.args.element).value == 0)
    return;
    var $element = $(event.args.element);
    var loader = false;
    var loaderItem = null;
    var children = $element.find('li');
    $.each(children, function () {
    var item = tree.jqxTree('getItem', this);
    if (item.label == 'Loading...') {
    loaderItem = item;
    loader = true;
    return false
    };
    });
    if (loader) {
    $.ajax({
    url: loaderItem.value,
    success: function (data, status, xhr) {
    var items = jQuery.parseJSON(data);
    tree.jqxTree('addTo', items, $element[0]);
    tree.jqxTree('removeItem', loaderItem.element);
    }
    });
    }
    });
    $('#jqxTree').on('checkChange', function (event)
    {
    var args = event.args;
    var checked = args.checked;
    var item = $('#jqxTree').jqxTree('getItem', args.element);
    if(checked)
    {
    $("#jqxTree").jqxTree('expandItem', $("#"+item.id)[0]);
    }
    else
    {
    if(item.level==0)
    {
    $('#jqxTree').jqxTree('collapseAll');
    $('#jqxTree').jqxTree('uncheckAll');
    }
    else if(item.level==1)
    {
    $("#jqxTree").jqxTree('collapseItem', $("#"+item.id)[0]);
    var children = $(args.element).find("li");
    $.each(children, function () {
    $("#jqxTree").jqxTree('uncheckItem', $("#"+this.id)[0]);
    });
    }
    else
    {
    $("#jqxTree").jqxTree('collapseItem', $("#"+item.id)[0]);
    }
    }
    });
    $(window).load()
    {
    if(${fromServer})
    {
    $("#jqxTree").jqxTree('expandItem', $("#cat1")[0]);
    }
    }
    });
    function submitForm()
    {
    var F = MM_findObj("form");
    var items = $('#jqxTree').jqxTree('getCheckedItems');
    var checkedItems = new Array();
    $.each(items, function () {
    checkedItems[checkedItems.length] = this.value;
    });
    var result="";
    for(var i=0; i<checkedItems.length; i++)
    {
    result+=checkedItems[i];
    if(i!=checkedItems.length-1)
    result+=",";
    }
    F.categorySelected.value=result;
    F.submit();
    }
    </script>
    </head>
    <body class='default'>
    <div id="jqxTree">
    </div>
    <br/><br/>
    <form:form method="post" name="form" id="form">
    <input type="hidden" name="categorySelected" id="categorySelected" />
    <input type="submit" value="submit" onclick="submitForm()" />
    <br/><br/>
    </form:form>
    </body>
    </html>

    And here is code in sever (I use java)

    @RequestMapping(value = "/productCategory", method = RequestMethod.GET)
    public void getTest(Model model, HttpServletRequest request,
    HttpSession session) {
    String level1 = " ["
    + " { label: \"First\", value:\"1\", id:\"cat1\", level:\"1\", items: [{ value: \"getDataCategory?id=1\", label: 'Loading...'}] },"
    + " { label: \"Second\", value:\"2\",level:\"1\", id:\"cat2\", items: [{ value: \"getDataCategory?id=2\", label: 'Loading...'}] }"
    + " ] ";
    model.addAttribute("level1", level1);
    model.addAttribute("fromServer", false);
    }
    @RequestMapping(value = "/getDataCategory", method = RequestMethod.GET)
    public void getDataCategory(Model model, HttpServletRequest request,
    HttpSession session) {
    String id = request.getParameter("id");
    String fromServer = request.getParameter("fromServer");
    String result = "";
    if (fromServer == null) {
    fromServer = "";
    }
    if (fromServer.equals("true")) {
    if (id.equals("1")) {
    result = " [{\"label\": \"Women\", \"value\":\"3\", \"level\":\"2\", \"id\":\"cat3\" },"
    + "{\"label\": \"Men\", \"value\":\"4\", \"level\":\"2\", \"id\":\"cat4\", \"checked\":\"true\" },"
    + "{\"label\": \"Girls\", \"value\":\"5\", \"level\":\"2\", \"id\":\"cat5\" },"
    + "{\"label\": \"Boys\", \"value\":\"6\", \"level\":\"2\", \"id\":\"cat6\" }]";
    }
    } else {
    if (id.equals("1")) {
    result = " [{\"label\": \"Women\", \"value\":\"3\", \"level\":\"2\", \"id\":\"cat3\" },"
    + "{\"label\": \"Men\", \"value\":\"4\", \"level\":\"2\", \"id\":\"cat4\", \"items\": [{ \"value\": \"getDataCategory?id=2\", \"label\": \"Loading...\"}] },"
    + "{\"label\": \"Girls\", \"value\":\"5\", \"level\":\"2\", \"id\":\"cat5\" },"
    + "{\"label\": \"Boys\", \"value\":\"6\", \"level\":\"2\", \"id\":\"cat6\" }]";
    } else if (id.equals("2")) {
    result = " [{\"label\": \"One\", \"value\":\"7\", \"level\":\"2\", \"id\":\"cat7\" },"
    + "{\"label\": \"Two\", \"value\":\"8\", \"level\":\"2\", \"id\":\"cat8\" },"
    + "{\"label\": \"Three\", \"value\":\"9\", \"level\":\"2\", \"id\":\"cat9\" },"
    + "{\"label\": \"Four\", \"value\":\"10\", \"level\":\"2\", \"id\":\"cat10\" }]";
    }
    }
    request.setAttribute("data", result);
    }
    @RequestMapping(value = "/productCategory", method = RequestMethod.POST)
    public void postDataCategory(Model model, HttpServletRequest request,
    HttpSession session) {
    String allCategorySelected = request.getParameter("categorySelected");
    String level1 = " ["
    + " { label: \"Men\", value:\"1\", id:\"cat1\", level:\"1\",checked:true, items: [{ value: \"getDataCategory?id=1&fromServer=true\", label: 'Loading...'}] },"
    + " { label: \"Women\", value:\"2\",level:\"1\", id:\"cat2\", items: [{ value: \"getDataCategory?id=2\", label: 'Loading...'}] }"
    + " ] ";
    model.addAttribute("level1", level1);
    model.addAttribute("fromServer", true);
    }

    Thank’s

    • This reply was modified 7 years, 4 months ago by  yehezqiel. Reason: edit tag code

    khrono_angel
    Member

    Hi, I’m getting the same error over Firefox… on Chrome and IE the console is getting this error

    “SCRIPT5007: No se puede establecer la propiedad ‘level’ de referencia nula o sin definir
    jqxtree.js, Línea 7 Carácter 31905”

    I’m using the code of the example in this post… i’m using jqwidgwets version 1.7

    best regards…


    Dimitar
    Participant

    Hello,

    We will test for the reported behaviour with the current version of jQWidgets. There has not been any issue with the previous version, 2.6.1.

    Best Regards,
    Dimitar

    jQWidgets team
    http://www.jqwidgets.com/


    Makla
    Participant

    I get error: Uncaught TypeError: Cannot set property ‘level’ of undefined.
    Details:

    Uncaught TypeError: Cannot set property ‘level’ of undefined jqx-all.js:7
    a.extend._refreshMapping jqx-all.js:7
    e jqx-all.js:7
    a.extend.addTo jqx-all.js:7
    a.jqx.invoke jqx-all.js:7
    a.jqx.jqxWidgetProxy jqx-all.js:7
    (anonymous function) jqx-all.js:7
    b.extend.each jquery-1.9.1.min.js:3
    b.fn.b.each jquery-1.9.1.min.js:3
    a.fn.(anonymous function) jqx-all.js:7
    (anonymous function) test.php:39
    b.event.dispatch jquery-1.9.1.min.js:3
    v.handle jquery-1.9.1.min.js:3
    b.event.trigger jquery-1.9.1.min.js:3
    (anonymous function) jquery-1.9.1.min.js:4
    b.extend.each jquery-1.9.1.min.js:3
    b.fn.b.each jquery-1.9.1.min.js:3
    b.fn.extend.trigger jquery-1.9.1.min.js:4
    a.extend._raiseEvent jqx-all.js:7
    (anonymous function) jqx-all.js:7
    r.complete jquery-1.9.1.min.js:5
    c jquery-1.9.1.min.js:3
    p.fireWith jquery-1.9.1.min.js:3
    u jquery-1.9.1.min.js:5
    b.fx.tick jquery-1.9.1.min.js:5

    Source code:

    <!DOCTYPE html>
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <script src="Framework/Scripts/jquery-1.9.1.min.js"></script>
    <script src="Framework/Scripts/jqwidgets/jqx-all.js"></script>
    <link rel="stylesheet" href="Framework/Styles/jqx.base.css" type="text/css" />
    <script type="text/javascript">
    $(document).ready(function () {
    // Create jqxTree
    var tree = $('#jqxTree');
    var source = [{ label: "Root", expanded: true,
    items: [
    { label: "Root Folder 1", items: [{ value: "ajax1.htm", label: 'Loading...'}] },
    { label: "Root Folder 2", items: [{ value: "ajax2.htm", label: 'Loading...'}] }
    ]
    }];
    tree.jqxTree({ source: source, width: 200 });
    tree.bind('expand', function (event) {
    var label = tree.jqxTree('getItem', event.args.element).label;
    var $element = $(event.args.element);
    var loader = false;
    var loaderItem = null;
    var children = $element.find('ul:first').children();
    $.each(children, function () {
    var item = tree.jqxTree('getItem', this);
    if (item && item.label == 'Loading...') {
    loaderItem = item;
    loader = true;
    return false
    };
    });
    if (loader)
    {
    var items = new Array();
    items.push({label: 'l', value: 'v', items: [{label: "Nalagam...", value: "nalagam"}]})
    tree.jqxTree('addTo', items, $element[0]);
    tree.jqxTree('removeItem', loaderItem.element);
    }
    });
    });
    </script>
    </head>
    <body class='default'>
    <div id="jqxTree">
    </div>
    </body>
    </html>

    Peter Stoev
    Keymaster

    Hi Makla,

    Please, see this Online Sample: http://www.jqwidgets.com/jquery-widgets-demo/demos/jqxtree/ajaxloading.htm?web. It shows how the jqxTree Items can be loaded on demand.

    Best Regards,
    Peter Stoev

    jQWidgets Team
    http://www.jqwidgets.com/


    Makla
    Participant

    Why is this not OK?

    var items = new Array();
    items.push({label: 'l', value: 'v', items: [{label: "Nalagam...", value: "nalagam"}]})
    tree.jqxTree('addTo', items, $element[0]);

    I am loading all kind of staff on demand. So I want to create items manually. I don’t see any difference between my code and the example code. My code is based on: load on demand example.


    Makla
    Participant

    I don’t understand this. First is OK and second is with error.

    tree.jqxTree('addTo', { label: 'Item', value: 'value' }, $element[0]);	//OK
    tree.jqxTree('addTo', { label: 'Item', value: 'value', items: [{label: "Nalagam...", value: "nalagam"}]}, $element[0]); //error

    reyhan
    Participant

    Hi, i have this issue too!
    When i clicked on arrow to load node’s children, node has collapsed quickly.
    I’m using jqwidget v6.1.0, jqxtree component.

    this is my code:

    function TreeNode(id, parentid, text, value) {
    var self = this;
    self.id = id;
    self.parentid = parentid;
    self.text = text;
    self.value = value;
    }

    function toId(input) {
    return input == null ? “-1″ : input + ”;
    }

    var mydata = {
    UserId: userid
    }
    $.ajax({
    url: “api/dashboard/getTreeRoot”,
    type: “Post”,
    data: mydata,
    async: false
    })
    .done(function (tree) {
    $(‘#jqxLoader’).jqxLoader(‘close’);
    self.showLoader(false);

    var nodes = [];
    for (var i in tree) {

    var node = tree[i];
    nodes.push(new TreeNode(
    toId(node.FldId),
    toId(node.FldParentId),
    node.FldNameFarsi,
    node.FldId));
    }
    var source =
    {
    datatype: “json”,
    datafields: [
    { name: ‘id’ },
    { name: ‘parentid’ },
    { name: ‘text’ },
    { name: ‘value’ }
    ],
    id: ‘id’,

    localdata: nodes
    };
    var dataAdapter = new $.jqx.dataAdapter(source);
    dataAdapter.dataBind();
    var records = dataAdapter
    .getRecordsHierarchy(‘id’, ‘parentid’, ‘items’, [{ name: ‘text’, map: ‘label’ }]);
    $(‘#jqxTree’)
    .jqxTree({
    source: records,
    width: ‘100%’,
    height: ‘320px’,
    rtl: true,
    checkboxes: true,
    hasThreeStates: true,
    theme: ‘material’
    });
    }).fail(function () {

    });

Viewing 15 posts - 1 through 15 (of 18 total)

You must be logged in to reply to this topic.