Angular: директива с bindToController «теряет» данные

У меня есть директива actionButtons:

function actionButtons(){
    'use strict';
    return {
        scope: {},
        restrict: 'AE',
        bindToController: {
            itemId: '@',
            itemDescription: '@',
            actionsText: '@',
            previewAction: '&',
            previewText: '@',
            editAction: '&',
            editText: '@',
            removeAction: '&',
            removeText: '@'
        },
        controller: ActionButtonsController,
        controllerAs: 'actionButtonsCtrl',
        templateUrl: 'src/views/directives/actionButtons.html'
    };
}

С контроллером ActionButtonsController:

/**
 *
 * @constructor
 */
function ActionButtonsController() {
    'use strict';
    var viewModel = this;
    //not important assertions
    }
    /**
     *
     * @type {boolean}
     */
    viewModel.hasItemDescription = typeof viewModel.itemDescription === 'string' &&
        viewModel.itemDescription.length > 0;
    /**
     *
     * @type {string}
     */
    viewModel.previewText = viewModel.previewText || 'preview';
    /**
     *
     * @type {string}
     */
    viewModel.editText = viewModel.editText || 'edit';
    /**
     *
     * @type {string}
     */
    viewModel.removeText = viewModel.removeText || 'remove';
    /**
     *
     * @type {string}
     */
    viewModel.actionsText = viewModel.actionsText || 'Actions';

    viewModel.preview = function() {
        viewModel.previewAction();
    };

    viewModel.edit = function() {
        viewModel.editAction();
    };

    viewModel.remove = function() {
        viewModel.removeAction();
    };
}

И часть его шаблона с кнопкой:

<div class="visible-xs-block btn-group" data-dropdown>
<button class="btn btn-block btn-primary" id="{{::(actionButtonsCtrl.itemId)}}" type="button"
        data-dropdown-toggle aria-haspopup="true">
    {{actionButtonsCtrl.actionsText}} <span class="sr-only" data-ng-if="::actionButtonsCtrl.hasItemDescription">
        for {{::(actionButtonsCtrl.itemDescription)}}</span></button>
</div>

И вот как я называю это в приложении:

<td class="col-md-3 col-xs-3 text-center">
    <div data-action-buttons
         data-item-id="{{author.id + '_' + author.name + '_' + author.surname}}"
         data-item-description="{{author.name + ' ' + author.surname}}"
         data-preview-action="authorCtrl.preview(author)"
         data-edit-action="authorCtrl.edit(author)"
         data-remove-action="authorCtrl.remove(author)"
        ></div>
</td>

А вот проблемы: как видно из кода контроллера, например actionsText не требуется, если его нет то будет установлено Actions. itemDescription также не требуется. Но если я указываю itemDescription, то он виден в HTML DOM все время, а Actions ведет себя очень странно для меня: ему установлено значение по умолчанию Actions, но он не виден в HTML DOM. Разница между этими двумя заключается в том, что actionsText привязан к this в явном виде кода контроллера, но я думал, что это поведение по умолчанию с bindToController, и это то, что я должен делать, когда хочу установить значение по умолчанию, где значение отсутствует. Кроме того, когда я отлаживаю его (например, вызывая одну из функций), actionsText имеет значение undefined, несмотря на то, что если я отлаживаю его при его создании, он устанавливает значение по умолчанию Actions. Не работает как при одноразовой привязке (с ::), так и в обычных ситуациях. Возможно, это что-то с scope: {} из кода директивы, но я не могу понять и надеюсь на вашу помощь - заранее спасибо. P.S. Пробовал вернуть переменную viewModel из контроллера - не помогло. P.S. 2 Хорошо работает, если указано actionsText (как data-actions-text={{'Something'}})


person Radek Anuszewski    schedule 25.07.2015    source источник


Ответы (1)


Вы используете bindToController, которые косвенно добавляют значения области действия в контекст контроллера this. Но эта проблема возникает из-за того, что вы используете символ @ внутри выражения bindToController.

Всякий раз, когда есть случай с controllerAs, bindToController и прицелом с @, angular обрабатывает эту вещь немного по-другому.

На самом деле, когда вы используете @ для переменной области внутри изолированной области с controllerAs и bindToController, angular поставьте часы, используя $observe для выражения, заданного для этого значения attribute, угловой код для того же

Решение будет использовать $timeout для выполнения всех назначений, которые будут извлекаться с использованием @ значения изолированной области. Поскольку значение привязывается в следующем цикле цикла дайджеста после того, как выражение $observe будет оценено.

Код

function ActionButtonsController() {
    'use strict';
    var viewModel = this;
    $timeout(function() {
        viewModel.hasItemDescription = typeof viewModel.itemDescription === 'string' &&
            viewModel.itemDescription.length > 0;

        viewModel.previewText = viewModel.previewText || 'preview';

        viewModel.editText = viewModel.editText || 'edit';

        viewModel.removeText = viewModel.removeText || 'remove';

        viewModel.actionsText = viewModel.actionsText || 'Actions';
    })

    viewModel.preview = function() {
        viewModel.previewAction();
    };

    viewModel.edit = function() {
        viewModel.editAction();
    };

    viewModel.remove = function() {
        viewModel.removeAction();
    };
};

Это подробный ответ

person Pankaj Parkar    schedule 25.07.2015
comment
@Pneumokok Если вам нужен подробный ответ, вы можете посмотреть связанный ответ .. Это поможет прояснить вашу концепцию .. Рад помочь вам .. Спасибо :) - person Pankaj Parkar; 25.07.2015
comment
@Pankaj Parkar bindToController полезен, но что, если я все еще хочу выполнять некоторые операции DOM? Должен ли я снова использовать функцию ссылки? - person Levis; 19.01.2016
comment
@Levis Да .. вы должны .. потому что вы получите там скомпилированный элемент директивы angular .. что было бы безопаснее манипулировать DOM там. - person Pankaj Parkar; 19.01.2016
comment
@Pankaj Parkar Итак, если я использовал controllerAs:ctrl, могу ли я получить контроллер с помощью require:'ctrl' и ввести его в качестве четвертого аргумента в функцию ссылки? ..Потому что я хочу предотвратить использование параметра области действия в директиве - person Levis; 19.01.2016