javascript - 如何确保指令的链接函数在 Controller 之前运行?

标签 javascript angularjs controller angularjs-directive angularjs-scope

在我们的应用程序中,我们有一个通过简单路由加载的 View 。

$routeProvider
    .when('/', {
        template: require('./views/main.tpl.html'),
        controller: 'mainCtrl'
    })
    .otherwise({
        redirectTo: '/'
    });

这关联了 mainCtrl具有 View 的 Controller 。 View 如下所示:

<left-rail>
    <filter-sub-rail
        id="filter-rail"
        show-all-filter="isAdmin"
        components="components">
    </filter-sub-rail>
</left-rail>

<div class="endor-Page-content endor-Panel">
    <action-bar
        selected-components="selectedComponents"
        toggleable-columns="toggleableColumns"
        refresh-component-list="refreshComponentList()">
    </action-bar>
    <filter-pills></filter-pills>
    <div class="js-endor-content endor-Panel-content endor-Panel-content--actionBarHeight">
        <component-table
            components="components"
            selected-components="selectedComponents"
            toggleable-columns="toggleableColumns">
        </component-table>
    </div>
    <spinner id="cmSpinner" large="true" center="true"></spinner>
    <modal></modal>
</div>

倒数第三行包含 <spinner>指示。该指令在加载数据时创建一个旋转图形。它有一个名为 spinnerApi 的关联 Angular 服务。 。 spinner指令使用spinner API注册spinner,允许其他服务注入(inject)spinner API并调用showhide方法,传入 ID,以显示/隐藏所需的微调器。

mainCtrl有一个函数在 Controller 运行时开始加载一些数据。

//spinnerApi.show('spinner1');
var data = Segment.query({
    /*...truncated for brevity...*/
}, function () {
    $scope.components = data;
    spinnerApi.hide('spinner1');
});

您可以看到第一次调用 spinnerApi.show被注释掉了。这是因为此时 spinner 指令尚未运行其链接函数,并且 spinner 尚未向 API 注册。如果我取消注释该行,我会得到一个异常,因为还没有名为 spinner1 的微调器。但是,当回调从查询运行时,微调器可用并且调用成功。

在我开始在 Controller 中加载数据并避免这种竞争条件之前,如何确保微调器指令运行并使用 API 注册微调器?

最佳答案

换个 Angular 思考:

让您的 Controller 在范围上发布一个标志,表示 api 是否正在加载。将此标志传递给模板中的指令,并观察它是否在指令链接函数中切换微调器。在处理元素显示(DOM 渲染优化)时,优先使用 prelink 函数而不是 poSTLink 函数。在观察者外部的预链接时间设置微调器可见性!否则,它将等待第一个摘要循环发生,以隐藏您已经支付了显示一次费用的微调器!

如果多种行为可能影响此显示标志,请创建一个服务来保存此标志,在 Controller 的范围内发布此服务,并提供该标志作为模板中指令的输入。在指令中注入(inject)此服务意味着微调器指令与其可见性条件之间存在过多的耦合。

<小时/>

问题作者编辑:

这个答案给了我一个想法,效果很好,而且看起来相当简单。我不希望 Controller 或指令执行任何奇怪的等待逻辑,因此在 spinnerApi 服务中应该发生一些事情是有道理的(该指令应该可以在应用程序)。

这是我的 spinnerApi 服务,如果 spinnerId 尚未注册,则修改为队列隐藏/显示/切换事件。当 register 方法运行时,它会在队列中查找是否有任何事情要做。

module.exports = angular.module('shared.services.spinner-api', [])
    // Simple API for easy spinner control.
    .factory('spinnerApi', function () {
        var spinnerCache = {};
        var queue = {};
        return {
            // All spinners are stored here.
            // Ex: { spinnerId: isolateScope }
            spinnerCache: spinnerCache,

            // Registers a spinner with the spinner API.
            // This method is only ever really used by the directive itself, but
            // the API could be used elsewhere if necessary.
            register: function (spinnerId, spinnerData) {

                // Add the spinner to the collection.
                this.spinnerCache[spinnerId] = spinnerData;

                // Increase the spinner count.
                this.count++;

                // Check if spinnerId was in the queue, if so then fire the
                // queued function.
                if (queue[spinnerId]) {
                    this[queue[spinnerId]](spinnerId);
                    delete queue[spinnerId];
                }

            },

            // Removes a spinner from the collection.
            unregister: function (spinnerId) {
                if (!this.spinnerCache[spinnerId]) throw new Error('Spinner "' + spinnerId + '" does not exist.');
                delete this.spinnerCache[spinnerId];
            },

            // Show a spinner with the specified spinnerId.
            show: function (spinnerId) {
                if (!this.spinnerCache[spinnerId]) {
                    queue[spinnerId] = 'show';
                    return;
                }
                this.spinnerCache[spinnerId].visible = true;
            },

            // Hide a spinner with the specified spinnerId.
            hide: function (spinnerId) {
                if (!this.spinnerCache[spinnerId]) {
                    queue[spinnerId] = 'hide';
                    return;
                }
                this.spinnerCache[spinnerId].visible = false;
            },

            // Hide/show a spinner with the specified spinnerId.
            toggle: function (spinnerId) {
                if (!this.spinnerCache[spinnerId]) {
                    queue[spinnerId] = 'toggle';
                    return;
                }
                this.spinnerCache[spinnerId].visible = !this.spinnerCache[spinnerId].visible;
            },

            // Show all spinners tracked by the API.
            showAll: function () {
                for (var key in this.spinnerCache) {
                    this.show(key);
                }
            },

            // Hide all spinners tracked by the API.
            hideAll: function () {
                for (var key in this.spinnerCache) {
                    this.hide(key);
                }
            },

            // Hide/show all spinners tracked by the API.
            toggleAll: function () {
                for (var key in this.spinnerCache)
                    this.spinnerCache[key].visible = !this.spinnerCache[key].visible;
            },

            // The number of spinners currently tracked by the API.
            count: 0
        };
    });

关于javascript - 如何确保指令的链接函数在 Controller 之前运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22698112/

相关文章:

javascript - 由 JQuery 选择的 Primefaces 复选框无法正常工作

javascript - 在饼图图像上创建链接

javascript - 将相关对象连接到一个对象数组中? (javascript)

javascript - 在 Angularjs 中加载外部模块(第三方库)

PHP MVC 设计 - 对同一 url/ Controller 的多个操作

javascript - 为什么我的 jsp 页面无法识别我的 Angular Controller ?

laravel-5 - 在 Laravel 5.4 Controller 构造函数中获取用户

javascript - 如何在短代码中使用 javascript 变量?

javascript - Angularjs 中的 ng-select 错误

javascript - 如何将对象插入 Firebase Forge? - AngularFire 0.8.0 - Thinkster - 第 7 章