Angularjs Angular 1.5组件$postLink在中使用templateUrl时过早触发

Angularjs Angular 1.5组件$postLink在中使用templateUrl时过早触发,angularjs,components,lifecycle,Angularjs,Components,Lifecycle,我随后了解了Angular的1.5组件postLink事件 我是在一家公司工作的。以下是选项卡组件的代码: controller: function () { this.$onInit = function () { console.log("$onInit"); this.tabs = []; }; this.addTab = function addTab(tab) { console.log("addTab"); this.tabs.push(tab); }; this.s

我随后了解了Angular的1.5组件postLink事件

我是在一家公司工作的。以下是选项卡组件的代码:

controller: function () {
this.$onInit = function () {
  console.log("$onInit");
  this.tabs = [];
};
this.addTab = function addTab(tab) {
  console.log("addTab");
  this.tabs.push(tab);
};
this.selectTab = function selectTab(index) {
  for (var i = 0; i < this.tabs.length; i++) {
    this.tabs[i].selected = false;
  }
  this.tabs[index].selected = true;
};
this.$postLink = function () {
  console.log("$postLink. nr of tabs added: " + this.tabs.length);

  this.selectTab(this.selected);
};
}
/tabs/tabs.component.ts

namespace MainApp {
const mainApp = angular.module("mainApp");

class TabComponent implements ng.IComponentOptions {
    public templateUrl: string | ng.Injectable<(...args: any[]) => string>;
    public controller: any;
    public controllerAs: string;
    public transclude: boolean;
    public bindings: any;
    public require: any;

    constructor() {
        this.templateUrl = ["rootUrl", (rootUrl) => rootUrl +  "app/uitrijregelingBerekening/tabs/tab/tab.html"];
        this.controller = TabController;
        this.transclude = true;
        this.bindings = {
            label: "@",
        };
        this.require = {
            tabs: "^^",
        };
    }
}

mainApp.component("tab", new TabComponent());

}
namespace MainApp {
const mainApp = angular.module("mainApp");

class TabsComponent implements ng.IComponentOptions{
    public templateUrl: string | ng.Injectable<(...args: any[]) => string>;
    public controller: any;
    public controllerAs: string;
    public bindings: any;
    public transclude: boolean;

    constructor() {
        this.templateUrl = ["rootUrl", (rootUrl) => rootUrl +  "app/uitrijregelingBerekening/tabs/tabs.html"];
        this.controller = TabsController;
        this.bindings = {
            selected:"@",
        };
        this.transclude = true;
    }
}

mainApp.component("tabs", new TabsComponent());

}
namespace MainApp{
常量mainApp=角度模块(“mainApp”);
类TabsComponent实现ng.IComponentOptions{
公共模板URL:string | ng.Injectable string>;
公共控制人:任何;
公共控制器:字符串;
公共约束:任何;
公共转置:布尔;
构造函数(){
this.templateUrl=[“rootUrl”,(rootUrl)=>rootUrl+“app/uitrijregelingBerekening/tabs/tabs.html”];
this.controller=选项卡控制器;
此文件的绑定={
已选定:“@”,
};
this.transclude=true;
}
}
mainApp.component(“制表符”,新制表符component());
}
/tabs/tabs.controller.ts

namespace MainApp {
interface ITabBindings {
    label: string;
}

export class TabController implements ITabBindings {
    public label: string;
    private tabs: TabsController;

    public tab: any;

    constructor() {
    }

    public $onInit() {
        this.tab = {
            label: this.label,
            selected: false
        };
        this.tabs.addTab(this.tab);
    }
}
}
namespace MainApp {
export interface ITabsBindings {
    selected: number;
}

export class TabsController implements ITabsBindings {
    public selected: number;
    public tabs: Array<any>;

    private scope: any;

    static $inject = ["$scope"];
    constructor($scope: ng.IScope) {
        this.scope = $scope;

    }

    public $onInit() {
        console.log("$onInit");
        this.tabs = new Array<any>();
    }

    public addTab(tab: any) {
        console.log("addTab");

        this.tabs.push(tab);
    }

    public selectTab(index: number) {
        for (var i = 0; i < this.tabs.length; i++) {
            this.tabs[i].selected = false;
        }
            this.tabs[index].selected = true;
    }

    public $postLink() {
        console.log("$postLink. nr of tabs added: " + this.tabs.length);

        this.selectTab(this.selected);
    }

}
}
namespace MainApp{
导出接口ITabsBindings{
选定:编号;
}
导出类TabsController实现ITabsBindings{
公众选择:数字;
公共选项卡:数组;
私人范围:任何;
静态$inject=[“$scope”];
构造函数($scope:ng.IScope){
this.scope=$scope;
}
公共$onInit(){
console.log(“$onInit”);
this.tabs=新数组();
}
公共添加选项卡(选项卡:任意){
console.log(“addTab”);
这个.tabs.push(tab);
}
公共选择选项卡(索引:编号){
对于(var i=0;i
模板是相同的

现在控制台输出为:

  • $onInit
  • $postLink。已添加标签数量:0
  • angular.js:13920 TypeError:无法设置未定义的属性“selected”
  • 地址表
  • 地址表
  • 地址表

我在这里遗漏了什么吗?

好吧,您现在使用的是不同的方法。在您将其推入一个控制器中的阵列之前。现在您有了两个组件和控制器

从Typescript文档来看,这是您的问题

请注意,包含templateUrl指令的子元素不会 已编译并链接,因为它们正在等待 异步加载的模板及其自己的编译和链接 已暂停,直到发生此情况。


与其使用
require
,不如将
选项卡
数组绑定到子项。

@kuhnroyal的答案在这里是正确的。但我想发布一篇后续文章,因为它可能对其他有同样问题的人有用。我已经找到了一个解决方案,允许我在单独的文件中使用模板(这提高了可维护性),但仍然使用模板属性来保证postLink事件的正确顺序


我现在处理角度的对象。关键是在angular应用程序启动时预加载所有模板。然后使用
$templateCache.get
方法填充组件的模板属性。这让我找到了解决方案。

在javascript代码中,我还使用了两个组件和控制器。设置基本相同。我之所以使用require,是因为我希望能够在选项卡中转移自定义内容。但是关于templateUrl的子元素被异步加载的注释就是答案!事实上,如果我切换到文字模板,它会工作!
    /**
     * Called after this controller's element and its children have been linked. Similar to the post-link function this
     * hook can be used to set up DOM event handlers and do direct DOM manipulation. Note that child elements that contain
     * templateUrl directives will not have been compiled and linked since they are waiting for their template to load
     * asynchronously and their own compilation and linking has been suspended until that occurs. This hook can be considered
     * analogous to the ngAfterViewInit and ngAfterContentInit hooks in Angular 2. Since the compilation process is rather
     * different in Angular 1 there is no direct mapping and care should be taken when upgrading.
     */
    $postLink?(): void;