angular-bootstrap-nav-tree icon indicating copy to clipboard operation
angular-bootstrap-nav-tree copied to clipboard

Incorrect working with lazy load data

Open vmamaev opened this issue 12 years ago • 15 comments

..controller_start...

MyModel.get_tree(function(data){ $scope.example_treedata = data })

..controller_end...

In view: abn-tree header="" tree-data="example_treedata" icon-leaf="icon-file" on-select="my_default_handler(branch)" expand-level="2" initial-selection="2"></abn-tree

"Initial-selection" and "Exand-level" doesn't work, but tree is rendered.

vmamaev avatar Oct 04 '13 22:10 vmamaev

This is true, but I am not sure what to do about it ( if anything ). The problem is that "expand-level" and "initial-selection" are only applied when the tree is first created. You can lazy-load the tree data, or you can modify or entirely replace the tree data at any time. How would the tree know when ( and whether ) it should apply the "initial-selection" and "expand-level" ? Maybe it should keep track of whether it is "empty", and then watch the tree data, and then, only when it changes from empty to not-empty, it could apply the "initial-selection" and "expand-level". Would that work?

nickperkinslondon avatar Nov 03 '13 17:11 nickperkinslondon

I have tried, works like this (may be low-performance method, but it works for me): used: scope.$watch('treeData', function (newval, oldval) {...})

var module;

module = angular.module('angularBootstrapNavTree', []);

module.directive('abnTree', function($timeout) {
  return {
    restrict: 'E',
    templateUrl: 'abn_tree_template.html',
    scope: {
      treeData: '=',
      onSelect: '&',
      initialSelection: '=',
      fieldSelection: '='
    },
    link: function(scope, element, attrs) {
      var expand_level, for_each_branch, on_treeData_change, select_branch, selected_branch, on_initialSelection_change;

      scope.$watch('treeData', function (newval, oldval) {
        if (newval) {
          if (attrs.iconExpand == null) {
            attrs.iconExpand = 'icon-plus';
          }
          if (attrs.iconCollapse == null) {
            attrs.iconCollapse = 'icon-minus';
          }
          if (attrs.iconLeaf == null) {
            attrs.iconLeaf = 'icon-chevron-right';
          }
          if (attrs.expandLevel == null) {
            attrs.expandLevel = '3';
          }
          if (attrs.fieldSelection == null) {
            attrs.fieldSelection = 'label';
          }
          expand_level = parseInt(attrs.expandLevel, 10);
          scope.header = attrs.header;

          if (!scope.treeData) {
            alert('no treeData defined for the tree!');
          }
          if (scope.treeData.length == null) {
            if (treeData.label != null) {
              scope.treeData = [treeData];
            } else {
              alert('treeData should be an array of root branches');
            }
          }
          for_each_branch = function(f) {
            var do_f, root_branch, _i, _len, _ref, _results;
            do_f = function(branch, level) {
              var child, _i, _len, _ref, _results;
              f(branch, level);
              if (branch.children != null) {
                _ref = branch.children;
                _results = [];
                for (_i = 0, _len = _ref.length; _i < _len; _i++) {
                  child = _ref[_i];
                  _results.push(do_f(child, level + 1));
                }
                return _results;
              }
            };
            _ref = scope.treeData;
            _results = [];
            for (_i = 0, _len = _ref.length; _i < _len; _i++) {
              root_branch = _ref[_i];
              _results.push(do_f(root_branch, 1));
            }
            return _results;
          };
          for_each_branch(function(b, level) {
            b.level = level;
            return b.expanded = b.level < expand_level;
          });
          selected_branch = null;
          select_branch = function(branch) {
            if (branch !== selected_branch) {
              if (selected_branch != null) {
                selected_branch.selected = false;
              }
              branch.selected = true;
              selected_branch = branch;
              if (branch.onSelect != null) {
                return $timeout(function() {
                  return branch.onSelect(branch);
                });
              } else {
                if (scope.onSelect != null) {
                  return $timeout(function() {
                    return scope.onSelect({
                      branch: branch
                    });
                  });
                }
              }
            }
          };
          scope.user_clicks_branch = function(branch) {
            if (branch !== selected_branch) {
              return select_branch(branch);
            }
          };
          on_initialSelection_change = function(newVal, oldVal){
            if ( newVal ) {
              attrs.initialSelection = newVal
              if (attrs.initialSelection != null) {
                for_each_branch(function(b) {
                  if (b[attrs.fieldSelection] == attrs.initialSelection) {
                    return select_branch(b);
                  }
                });
              }
            }
          };
          scope.tree_rows = [];
          on_treeData_change = function() {
            var add_branch_to_list, root_branch, _i, _len, _ref, _results;
            scope.tree_rows = [];
            for_each_branch(function(branch) {
              if (branch.children) {
                if (branch.children.length > 0) {
                  return branch.children = branch.children.map(function(e) {
                    if (typeof e === 'string') {
                      return {
                        label: e,
                        children: []
                      };
                    } else {
                      return e;
                    }
                  });
                }
              } else {
                return branch.children = [];
              }
            });
            for_each_branch(function(b, level) {
              if (!b.uid) {
                return b.uid = "" + Math.random();
              }
            });
            add_branch_to_list = function(level, branch, visible) {
              var child, child_visible, tree_icon, _i, _len, _ref, _results;
              if (branch.expanded == null) {
                branch.expanded = false;
              }
              if (!branch.children || branch.children.length === 0) {
                tree_icon = attrs.iconLeaf;
              } else {
                if (branch.expanded) {
                  tree_icon = attrs.iconCollapse;
                } else {
                  tree_icon = attrs.iconExpand;
                }
              }
              scope.tree_rows.push({
                level: level,
                branch: branch,
                label: branch.label,
                tree_icon: tree_icon,
                visible: visible
              });
              if (branch.children != null) {
                _ref = branch.children;
                _results = [];
                for (_i = 0, _len = _ref.length; _i < _len; _i++) {
                  child = _ref[_i];
                  child_visible = visible && branch.expanded;
                  _results.push(add_branch_to_list(level + 1, child, child_visible));
                }
                return _results;
              }
            };
            _ref = scope.treeData;
            _results = [];
            for (_i = 0, _len = _ref.length; _i < _len; _i++) {
              root_branch = _ref[_i];
              _results.push(add_branch_to_list(1, root_branch, true));
            }
            return _results;
          };

          scope.$watch('initialSelection', on_initialSelection_change, true);
          return scope.$watch('treeData', on_treeData_change, true);
        }
      });


    }
  };
});

vmamaev avatar Nov 07 '13 05:11 vmamaev

@vmamaev This worked for me (for now), but I agree, this isn't ideal. This is an async issue I believe, unfortunately, over my head at this moment to fix.

michaelryancaputo avatar Nov 26 '13 16:11 michaelryancaputo

Works for me, too :+1:

goloroden avatar Nov 27 '13 14:11 goloroden

Hi,

Seems to me that atiertant's code in issue #16 does much of the job without the need to keep the old data, but as-is the branches will re-expand whenever the user tries to close a branch (because closing a branch changes the data and therefore we re-run the on_treeData_change).

I found that that wrapping atiertant's code in a check for tree_rows.length solved my problems with lazy-loaded data:

if (!scope.tree_loaded && scope.tree_rows.length > 0) {
            scope.tree_loaded = true;
            for_each_branch(function(b, level) {
                b.level = level;
                return b.expanded = b.level < expand_level;
            });
            if (attrs.initialSelection != null) {
                for_each_branch(function(b) {
                    if (b.label === attrs.initialSelection) {
                        return select_branch(b);
                    }
                });        
            }
        }

rpdai avatar Dec 06 '13 19:12 rpdai

Hi,

you are right ! i got a bug with user interaction ! but your code works only once if scope change before user click and don't change after ... i change my code to this:

on top of link function:

var user_action = false;

at the scope.user_clicks_branch function,i set user_action to true and add a function:

scope.user_clicks_branch = function(branch) {
    user_action = true;
    if (branch !== selected_branch) {
        return select_branch(branch);
    }
};
scope.user_expand_branch = function(branch) {
    user_action = true;
    branch.expanded = !branch.expanded;
};

the code at the end of the on_treeData_change function become:

if (!user_action) {
        scope.tree_loaded = true;
        for_each_branch(function(b, level) {
            b.level = level;
            return b.expanded = b.level < expand_level;
        });
        if (attrs.initialSelection != null) {
            for_each_branch(function(b) {
                if (b.label === attrs.initialSelection) {
                    return select_branch(b);
                }
            });        
        }
}
else {
    user_action = true;
}

and the template to use the user_expand_branch function:

<ul class="nav nav-list nav-pills nav-stacked abn-tree">
  <li ng-repeat="row in tree_rows | filter:{visible:true} track by row.branch.uid" ng-animate="'abn-tree-animate'" ng-class="'level-' + {{ row.level }} + (row.branch.selected ? ' active':'')" class="abn-tree-row">
    <a ng-click="user_clicks_branch(row.branch)">
      <i ng-class="row.tree_icon" ng-click="user_expand_branch(row.branch)" class="indented tree-icon"> </i>
      <span class="indented tree-label">{{ row.label }}</span>
    </a>
  </li>
</ul>

atiertant avatar Dec 12 '13 13:12 atiertant

Cool! Does the else user_action=true only run if it is already true though? Or is it just too late at night for me to think...

rpdai avatar Dec 12 '13 23:12 rpdai

this is an error:

else {
    user_action = false;
 }

sorry !

atiertant avatar Dec 13 '13 11:12 atiertant

I'm running into this issue as well. Any chance to have this fixed in master?

magro avatar Jun 25 '14 20:06 magro

@atiertant 's solution works fine for me. Thanks!

ssilvana avatar Jul 10 '14 17:07 ssilvana

I used ng-if check so that tree is initialized and rendered only when the data is loaded. It worked for me.

sachinsawant71 avatar Aug 18 '15 01:08 sachinsawant71

<abn-tree tree-data="my_data" ng-if="isInit" tree-control="my_tree" on-select="my_tree_handler(branch)" expand-level="2" initial-selection="Granny Smith"></abn-tree>
$scope.isInit=false;
setTimeout(function(){
  $scope.my_data = treedata_avm;
  $scope.isInit=true;
  $scope.$apply('isInit');
},1000);

CaiLifeng avatar Nov 03 '15 14:11 CaiLifeng

@CaiLifeng 's solution works fine for me. Thanks!

tonyGitHubRunoob avatar Jun 14 '16 08:06 tonyGitHubRunoob

@CaiLifeng 's solution works fine for me too. But How I could set the initial-selection dynamically after to upload the data?

Goose1985 avatar Jul 25 '16 18:07 Goose1985

I figure out this problem by adding children to the branch when it is clicked.the solution could click this page. http://blog.csdn.net/baidu_35407267/article/details/52457779

guguji5 avatar Feb 10 '17 02:02 guguji5