文档章节

解决Angular的递归指令问题

写程序的阿狸
 写程序的阿狸
发布于 2015/09/19 04:44
字数 778
阅读 448
收藏 12

半夜三更睡不着,记录一下昨天工作遇到的问题。

出于项目的需要,写了一个递归的指令。这东西居然导致chrome假死。看起来好严重,连强制退出都不行了,害我重启电脑


简单介绍一下背景:

首先是有一个树状的数据结构,大约是这样子:

{
    id:xx,
    children:{
        id:yy,
        children:{...}
    }
}



想在页面显示这个数据,一般的思路就是写一个指令嘛,模版大约是这个样子的( 假设指令的名字就是nodeDirective):
<div>
    <label>{{node.id}}</label>
    <div ng-if="node.children.length>0">
        <ul>
            <li ng-repeat="child in node.children">
                <node-directive node="child"></node-directive>
            </li>
        </ul>
    </div>
</div>



指令的代码:
angular.module('module', []).directive('nodeDirective', ..., function() {
    return {
        restrict:'E',
        scope:{node:'='},
        link:function(scope,elem,attrs) {
            // do something.
        }
    }
});



看上去没有神马问题,下一步当然是刷新浏览器页面,然后。。。死了,chrome死了死了的。一开始还怀疑是chrome的问题,以为打开太多tab了;还怀疑过是Mac系统的问题,想着这不是windows,怎么也死机了。好吧,后来证实是我多疑了,冤枉了他俩。

这时猜测是angular编译递归指令的bug。简单验证一下:把递归的html代码注释掉,再刷新浏览器页面,果然正常显示!居然能出这种错误,先鄙视一下AngularJS

毕竟我是用angular的初哥,遇到这种问题,只能先求助谷歌,找到两个解决方案:

1. http://stackoverflow.com/questions/14430655/recursion-in-angular-directives

这个方案在伟大的stackoverflow中搜到;具体步骤就是:

增加一个recursionHelper.js先:

module.factory('RecursionHelper', ['$compile', function($compile){
    return {
        /**
         * Manually compiles the element, fixing the recursion loop.
         * @param element
         * @param [link] A post-link function, or an object with function(s) registered via pre and post properties.
         * @returns An object containing the linking functions.
         */
        compile: function(element, link){
            // Normalize the link parameter
            if(angular.isFunction(link)){
                link = { post: link };
            }

            // Break the recursion loop by removing the contents
            var contents = element.contents().remove();
            var compiledContents;
            return {
                pre: (link && link.pre) ? link.pre : null,
                /**
                 * Compiles and re-adds the contents
                 */
                post: function(scope, element){
                    // Compile the contents
                    if(!compiledContents){
                        compiledContents = $compile(contents);
                    }
                    // Re-add the compiled contents to the element
                    compiledContents(scope, function(clone){
                        element.append(clone);
                    });

                    // Call the post-linking function, if any
                    if(link && link.post){
                        link.post.apply(null, arguments);
                    }
                }
            };
        }
    };
}]);



然后给原来的指令增加compile方法,把之前的link方法作为参数传入:

angular.module('module', []).directive('nodeDirective', ..., function() { 
    return {
        restrict:'E',
        scope:{node:'='},
        compile : function(element) {
                        return recursionHelper.compile(element,function(scope, elem, attr) {
                // do something.
            });
        }
    }
});



2. http://sporto.github.io/blog/2013/06/24/nested-recursive-directives-in-angular/

这个方案的思路是不使用递归指令,然后在link方法修改当前元素,增加孩子结点(这个结点就是之前递归使用的本指令)。可以说是曲线救国了。

模版修改为:

<div>
    <label>{{node.id}}</label>
</div>



指令修改为:


angular.module('module', []).directive('', ..., function() {
    return {
        restrict:'E',
        scope:{node:'='},
        link:function(scope,elem,attrs) {
            if (angular.isArray(scope.node.children)) {    
                elem.append("\
                   <ul> \
                    <li ng-repeat="child in node.children">\
                     <node-directive node="child"></node-directive>\
                    </li>\
                   </ul>\
                  ");  
                $compile(elem.contents())(scope)  
           }
           // do something.
        }
    }
});



个人比较喜欢第一个方案。第二个方案,是通过代码来修改dom了,这样做不优雅,应该尽量避免。

我是用第一个方案解决问题了,但是一个下午已经过去了。

© 著作权归作者所有

写程序的阿狸
粉丝 2
博文 7
码字总数 2558
作品 0
广州
高级程序员
私信 提问
《AngularJS学习整理》系列分享专栏

《AngularJS学习整理》系列分享专栏 《AngularJS学习整理》已整理成PDF文档,点击可直接下载至本地查阅 https://www.webfalse.com/read/201748.html 文章 教你用AngularJS框架一行JS代码实现...

开元中国2015
2018/11/09
190
0
ngular2 VS Angular4 深度对比:特性、性能

在Web应用开发领域,Angular被认为是最好的开源JavaScript框架之一。 Google的Angular团队已于3月23日发布了Angular4,而期待已久的Angular2版本则是之前版本的完全重构。 对于成熟的开发人员...

机器的心脏
2018/06/02
0
0
OSChina 技术专题之 AngularJS 更新版(201412)

Angular JS (Angular.JS) 是一组用来开发Web页面的框架、模板以及数据绑定和丰富UI组件。它支持整个开发进程,提供web应用的架构,无需进行手工DOM操作。 AngularJS很小,只有60K,兼容主流浏...

OSC编辑部
2014/10/17
11.2K
26
Angular.js 相关记录

AngularJS作用域文档:http://docs.angularjs.org/api/ng.$rootScope.Scope ng-view 指令的角色是为当前路由把对应的视图模板载入到布局模板中。 AngularJS内置过滤器:http://code.angular...

彭博
2014/04/25
309
2
学习 AngularJS (一)

进一步看入 kityminder-editor 部分了, 打开示例文件 index.html, 开头就是引入三个著名 js 开源库: jQuery.js, bootstrap.js, angular.js 这意味着我又得学习了解这些库都是干什么的了. 略知...

刘军兴
2015/12/04
235
0

没有更多内容

加载失败,请刷新页面

加载更多

Java 8 Optional:优雅地避免 NPE

本篇文章将详细介绍 Optional 类,以及如何用它消除代码中的 null 检查。在开始之前首先来看下什么是 NPE,以及在 Java 8 之前是如何处理 NPE 问题的。 空指针异常(NullPointException,简称...

武培轩
34分钟前
9
0
CountDownLatch实现的并发框架

目录结构 package com.**.**.base.support.executor;import lombok.NoArgsConstructor;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;imp......

MR_TE
35分钟前
13
0
学习记录(day06-事件、按键修饰符、计算属性)

[TOC] 1.1 事件修饰符/按键修饰符 vue 通过事件修饰符对dom事件细节进行控制 <标签 @事件.修饰符="函数"></标签>.prevent ---阻止浏览器默认行为.stop ---阻止浏览器事件冒泡.e...

庭前云落
55分钟前
9
0
006-Sigle-基于blockstack去中心化博客

本篇文章主要讲解有关基于Blockstack的Sigle是一个去中心化的博客项目; 官网地址:https://www.sigle.io/ Github地址:https://github.com/pradel/sigle 页面展示: 介绍: A beautiful de...

Riverzhou
今天
22
0
驰骋工作流引擎开发平台属性功能的隐藏显示介绍

关键字: 工作流程管理系统 工作流引擎 asp.net工作流引擎 java工作流引擎. 表单引擎 工作流功能说明 工作流设计 工作流快速开发平台 业务流程管理 bpm工作流系统 java工作流主流框架 自定义...

孟娟
今天
19
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部