1

I have actionButtons directive:

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

With ActionButtonsController controller:

/**
 *
 * @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();
    };
}

And part of his template, with button:

<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>

And that is how I call it in application:

<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>

And the problems is: as you can see from controller code, for example actionsText is not required, if is not present it will be set to Actions. itemDescription also is not required. But if I specify itemDescription it is visible in HTML DOM all the time, but Actions behaves in very strange way for me: it is set to default value Actions, but it is not visible in HTML DOM. The difference between this two is that actionsText is bound to this in controller's code explicity - but I thought that is default behavior with bindToController and this is what I should do when I want to set default value where value is not present. Also, when I debug it (for example by calling one of the function), actionsText has undefined value, despite the fact that if I debug it when it is created, it has set a default Actions value. It doesn't work both with one-time binding (with ::) and normal situations. Maybe it's something with scope: {} from directive's code, but I can't figure it out and I hope for your help - thank you in advance. P.S. I tried return viewModel variable from controller - it didn't help. P.S. 2 It works well if actionsText is specified (as data-actions-text={{'Something'}})

Radek Anuszewski
  • 1,812
  • 8
  • 34
  • 62

1 Answers1

1

You are using bindToController which indirectly add the scope values to controller this context. But this issue is happening because you are using @ symbol inside your bindToController expression.

Whenever there is case with controllerAs, bindToController & scope with @ angular handle this thing in sightly different way.

Actually when you use @ on scope variable inside isolated scope with controllerAs & bindToController angular put a watch using $observe on the expression given on that attribute value, angular code for same

The solution would use $timeout to do all assignment which are going to fetch using @ of isolated scope value. Because value gets bind in next digest cycle cycle after the $observe expression gets evaluated.

Code

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

This is detailed version answer

Community
  • 1
  • 1
Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299
  • @Pneumokok If you want detailed answer you could look at the linked answer.. That would help to clear your concept.. Glad to help you..Thanks :) – Pankaj Parkar Jul 25 '15 at 18:28
  • @Pankaj Parkar bindToController is useful but what if i still want to do some DOM operations?Must I use link function again? – Levis Jan 19 '16 at 07:11
  • @Levis yes..you should..because you will get the angular compiled directive element there..which would be safer thing to manipulate DOM over there. – Pankaj Parkar Jan 19 '16 at 07:12
  • @Pankaj Parkar So,if I have used controllerAs:"ctrl",may I fetch the controller by using require:'ctrl' and inject it as the fourth argument in link function?..Cuz I want to prevent using the scope option in a directive – Levis Jan 19 '16 at 08:14