新 AngularJS ng-ref 指令的陷阱

2024-01-20

The release of AngularJS V1.7.1* https://github.com/angular/angular.js/blob/master/CHANGELOG.md#171-momentum-defiance-2018-06-08 introduces the new ng-ref directive https://docs.angularjs.org/api/ng/directive/ngRef#overview. While this new directive enables users to easily do certain things, I see great potential for abuse and problems.

The ng-ref https://docs.angularjs.org/api/ng/directive/ngRef#overview属性告诉 AngularJS 在当前范围内发布组件的控制器。这对于让音频播放器等组件向同级组件公开其 API 非常有用。其播放和停止控件可以轻松访问。

第一个问题是播放器控件undefined在 - 的里面$onInit控制器的功能。

Initial vm.pl = undefined  <<<< UNDEFINED
Sample = [true,false]

对于依赖于可用数据的代码,我们该如何解决这个问题?

The DEMO http://plnkr.co/edit/Vt8zj589iuNYAjeNLq1E?p=preview

angular.module("app",[])
.controller("ctrl", class ctrl {
  constructor() {
    console.log("construct")
  }
  $onInit() {
    console.log("onInit", this.pl);
    this.initPL = this.pl || 'undefined';
    this.sample = this.pl || 'undefined';
    this.getSample = () => {
      this.sample = `[${this.pl.box1},${this.pl.box2}]`;
    }
  }
})
.component("player", {
  template: `
    <fieldset>
      $ctrl.box1={{$ctrl.box1}}<br>
      $ctrl.box2={{$ctrl.box2}}<br>
      <h3>Player</h3>
    </fieldset>
  `,
  controller: class player {
    constructor() {
      console.log("player",this);
    }
    $onInit() {
      console.log("pl.init", this)
      this.box1 = true;
      this.box2 = false;
    }
  },
})
<script src="//unpkg.com/[email protected] /cdn-cgi/l/email-protection/angular.js"></script>
<body ng-app="app" ng-controller="ctrl as vm">
    Initial vm.pl = {{vm.initPL}}<br>
    Sample = {{vm.sample}}<br>
    <button ng-click="vm.getSample()">Get Sample</button>
    <br>
    <input type="checkbox" ng-model="vm.pl.box1" />
      Box1 pl.box1={{vm.pl.box1}}<br>
    <input type="checkbox" ng-model="vm.pl.box2" />
      Box2 pl.box2={{vm.pl.box2}}<br>
    <br>
    <player ng-ref="vm.pl"></player>
</body>

获取对组件控制器的引用并不是什么新鲜事,当时的指令允许这样做,这根本不是问题,有必要拥有这样的功能,ng-ref只是帮助您从模板端执行此操作(与 Angular 2+ 的方式相同)。

然而,如果您需要准备好子组件,您应该使用$postLink()代替$onInit. $postLink在组件与其子组件链接后调用,这意味着ng-ref当它被调用时就会准备好。

所以你所要做的就是改变你的onInit像这样:

̶$̶o̶n̶I̶n̶i̶t̶(̶)̶ ̶{̶
$postLink() {
    console.log("onInit", this.pl);
    this.initPL = this.pl || 'undefined';
    this.sample = this.pl || 'undefined';
    this.getSample = () => {
      this.sample = `[${this.pl.box1},${this.pl.box2}]`;
    }
}

$postLink()- 链接此控制器的元素及其子元素后调用。与 post-link 函数类似,此钩子可用于设置 DOM 事件处理程序并进行直接 DOM 操作。请注意,包含 templateUrl 指令的子元素不会被编译和链接,因为它们正在等待其模板异步加载,并且它们自己的编译和链接已暂停,直到发生这种情况。这个钩子可以被认为类似于ngAfterViewInit and ngAfterContentInitAngular 中的钩子。由于 AngularJS 中的编译过程相当不同,因此没有直接映射,升级时应小心。

Ref.: 了解组件 https://docs.angularjs.org/guide/component

完整的工作片段可以在下面找到(我删除了所有console.log为了更清楚):

angular.module("app",[])
.controller("ctrl", class ctrl {
  constructor() {
    //console.log("construct")
  }
  $postLink() {
    //console.log("onInit", this.pl);
    this.initPL = this.pl || 'undefined';
    this.sample = this.pl || 'undefined';
    this.getSample = () => {
      this.sample = `[${this.pl.box1},${this.pl.box2}]`;
    }
  }
})
.component("player", {
  template: `
    <fieldset>
      $ctrl.box1={{$ctrl.box1}}<br>
      $ctrl.box2={{$ctrl.box2}}<br>
    </fieldset>
  `,
  controller: class player {
    constructor() {
      //console.log("player",this);
    }
    $onInit() {
      //console.log("pl.init", this)
      this.box1 = true;
      this.box2 = false;
    }
  },
})
<script src="//unpkg.com/[email protected] /cdn-cgi/l/email-protection/angular.js"></script>
<body ng-app="app" ng-controller="ctrl as vm">
    Initial vm.pl = {{vm.initPL}}<br>
    Sample = {{vm.sample}}<br>
    <button ng-click="vm.getSample()">Get Sample</button>
    <br>
    <input type="checkbox" ng-model="vm.pl.box1" />
      Box1 pl.box1={{vm.pl.box1}}<br>
    <input type="checkbox" ng-model="vm.pl.box2" />
      Box2 pl.box2={{vm.pl.box2}}<br>
    <player ng-ref="vm.pl"></player>
  </body>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

新 AngularJS ng-ref 指令的陷阱 的相关文章

随机推荐

  • 在 R 中创建空间数据

    我有一个 100 x 200 米区域内物种及其大致位置的数据集 数据框的位置部分不是我认为可用的格式 在这个 100 x 200 米的矩形中 有 200 个 10 x 10 米的正方形 分别命名为 A 到 CV 每个 10 x 10 的正方
  • 如何动态添加导航栏到 jQuery Mobile 应用程序

    如何动态地将导航栏添加到我的 jquery 移动应用程序中 我希望能够从 javascript 将导航栏元素添加到 dom 然后解析它们 我发现我可以根据需要将元素添加到 DOM 然后在元素上调用 navbar 它将执行导航栏解析 例如我可
  • Ormlite Android 批量插入

    谁能解释一下为什么我的插入在 Ormlite 中花费了这么长时间 在桌面上的一个 SQLite 事务中执行 1 700 次插入只需不到一秒 然而 当使用 Ormlite for Android 时 大约需要 70 秒 并且我可以在调试消息中
  • .NET几何库[关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在 NET 中启动一个新项目 该项目需要一些几何算法 例如 检查点是否在多边形内部 贝塞尔曲线 线交
  • 在 C# 类库中使用 MATLAB MWArray.dll

    我正在尝试使用 dll 在 MATLAB 中使用 Matlab net Complier 构建 C 类库 但是每次初始化 MWArray dll 中的对象时程序都会引发异常 例如 MWNumericArray m new MWNumeric
  • json.dump 在看似有效的对象上抛出“TypeError:{...} 不是 JSON 可序列化”?

    背景 我正在编写一个 python 程序来管理我的音乐文件 它抓取目录并将文件及其元数据 通过诱变剂 以 JSON 编码 作为简单的 数据库 放入文件中 我的目录搜索很好 但是当我尝试保存数据库或编码为 JSON 时 它会抛出 TypeEr
  • 维护 web.config 文件

    我很想知道其他人如何维护已部署应用程序的 web config 文件 假设没有自动部署机制 这超出了这个问题的范围 因此 在开发过程中 一些开发人员可能会利用 web config 转换 构建 发布他们的项目 调试 发布 测试 实时配置 然
  • 如何撤消clearPackagePreferredActivities("com.android.launcher");

    我想做的是复制 ToddlerLock 应用程序的功能 我已经设法清除默认启动器 PackageManager localPackageManager getPackageManager localPackageManager clearP
  • 使用 Apollo/graphQL/React 访问和刷新令牌

    经过长时间的搜索 当访问令牌过期时 我为我的应用程序制定了这个解决方案 与其他服务的区别在于 我必须使用外部服务 在使用我的谷歌帐户登录时为我提供访问和刷新令牌 然后 当访问令牌过期时 我需要检索刷新令牌 将其发送到为我提供新访问和刷新令牌
  • C - 求结构的尺寸

    我被问到这个问题作为面试问题 无法回答 编写一个 C 程序来查找结构的大小 而不使用sizeof操作员 struct XYZ int x float y char z int main struct XYZ arr 2 int sz cha
  • ServiceStack.Text 是否提供 JSON 的漂亮打印?

    TL DR ServiceStack Text 中是否有内置方法来生成打印精美的 JSON 我在用ServiceStack Text https github com ServiceStack ServiceStack Text用于进行 J
  • 如何在 Angular2 的 Pipe 中将数组作为 arg 传递

    我创建了一个管道 其目的是根据标签列表过滤列表 Pipe name tagfilter export class TagFilterPipe implements PipeTransform transform items Event ar
  • 更改操作栏溢出的样式

    我在我当前的 android 应用程序中使用 Theme Holo 上面是我当前主题的溢出 UI 我想将溢出菜单的背景颜色自定义为 RGB 245 243 239 将字体颜色自定义为 RGB 64 64 64 以下是我正在使用的 style
  • 在 ActionBar 上放置一个进度条

    我试图在操作栏上放置一个不确定的进度栏 例如 我使用 actionView 来放置进度条 例如 Google 应用程序
  • 如何将模式模板的 let-c="close" 传递给其他组件的 html Angular 5

    我是 Angular 4 的新手 请帮助我 我有一个具有模式模板的组件 成分 import Component from angular core import NgbModal ModalDismissReasons from ng bo
  • Android studio 抛出 IOException:不允许操作

    现在 我正在为自己创建一个应用程序 它将数据附加到几个文件中 但是当我尝试创建文件 或者实际上打开它们 时 程序会抛出java io IOException Operation not permitted 如您所见 已授予存储权限 这个应用
  • pandas 是否会自动跳过行并进行大小限制?

    我们都知道这个问题 当你运行时出现内存错误 pandas 数据框的最大大小 https stackoverflow com questions 23569771 maximum size of pandas dataframe 442076
  • clang-format 何时断行继承列表?

    Clang format 总是将继承和类名放在同一行 无论我设置什么BreakInheritanceList to 我希望它以相同的方式格式化继承列表和构造函数初始值设定项列表 class Foo Parent int member pub
  • .NET 提供的有关 uri 和 url 的 api 的替代方案

    我最近意识到 使用 URL 和 URI 的 NET api 经常无法实现基本功能 至少很容易 包括 从相对路径生成 FQDN url 强制 https 或返回到http 获取网站的根 正确组合相对 URL 等等 是否有其他库可以将所有这些类
  • 新 AngularJS ng-ref 指令的陷阱

    The release of AngularJS V1 7 1 https github com angular angular js blob master CHANGELOG md 171 momentum defiance 2018