当使用templateUrl

时间:2017-01-10 12:34:05

标签: angularjs components lifecycle

我跟着this post熟悉了Angular的1.5组件postLink事件。

我的工作是plunker。这是选项卡组件的代码:

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);
};
}

控制台输出:

  • $的OnInit
  • addTab
  • addTab
  • addTab
  • $ postLink。添加了nr个标签:3

然而,当我尝试在打字稿中做同样的事情时,postLink事件会很快被触发。在将选项卡添加到选项卡组件之前,它会被触发。

以下是一些代码: /tabs/tab/tab.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());

}

/tabs/tab/tab.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);
    }
}
}

/tabs/tabs.component.ts

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());

}

/tabs/tabs.controller.ts

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);
    }

}
}

模板是一样的。

现在控制台输出是:

  • $的OnInit
  • $ postLink。添加了nr个标签:0
  • angular.js:13920 TypeError:无法设置未定义属性“已选择”
  • addTab
  • addTab
  • addTab

我在这里错过了什么吗?

2 个答案:

答案 0 :(得分:1)

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

我现在使用角度$templateCache对象。关键是在角度应用程序启动时预加载所有模板。然后使用$templateCache.get方法填充组件上的template-property。这post引导我解决这个问题。

答案 1 :(得分:0)

嗯,你现在正在使用不同的方法。在您将其推入一个控制器中的数组之前。现在你有两个组件和控制器。

从Typescript文档中,这是你的问题。

    /**
     * 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;
     

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

您应该将require数组绑定到子节点上,而不是使用tabs